async def answer_query(self, ctx, query, assumptions=[], small=False, debug=False): safe.sprint('wolfram|alpha :', ctx.author.name, ':', query) channel = ctx.channel author = ctx.author api = get_api(ctx.bot) # Filter out bad words enable_filter = False if not is_private(channel): enable_filter = await ctx.bot.settings.resolve('f-wolf-filter', channel, channel.guild, default='nsfw' not in channel.name) if enable_filter and wordfilter.is_bad(query): await ctx.send(FILTER_FAILURE) return # Perform the query try: async with ctx.typing(): units = await ctx.bot.keystore.get(f'p-wolf-units:{author.id}') result = await api.request(query, assumptions, imperial=(units == 'imperial'), debug=debug) except (wolfapi.WolframError, wolfapi.WolframDidntSucceed): await ctx.send(ERROR_MESSAGE_NO_RESULTS) except asyncio.TimeoutError: print('W|A timeout:', query) await ctx.send(ERROR_MESSAGE_TIMEOUT.format(query)) except aiohttp.ClientError as error: print('Wolf: HTTP processing error:', error.message) await ctx.send('The server threw an error. Try again in a moment.') except xml.parsers.expat.ExpatError as error: print('Wolf: XML processing error:', error) await ctx.send( 'The server returned some malformed data. Try again in a moment.' ) else: if len(result.sections) == 0: await ctx.send(ERROR_MESSAGE_NO_RESULTS) return is_dark = ( await ctx.bot.keystore.get(f'p-tex-colour:{author.id}')) == 'dark' sections_reduced = result.sections if not small else list( cleanup_section_list( itertools.chain( [find_first(section_is_input, result.sections, None)], list(filter(section_is_important, result.sections)) or [ find_first(section_is_not_input, result.sections, None) ]))) # Post images messages = [] for img in process_images(sections_reduced, is_dark): messages.append( await ctx.send(file=image_to_discord_file(img, 'result.png'))) await asyncio.sleep(1.05) # Assuptions are currently disabled because of a 'bug'. # I think it's that discord sends emoji reaction updates # on a different shard to the one that handles the channel # that the message is in, which means that the shard # receiving the notif doesn't know what to do with the info # it receives. embed, show_assuptions = await self.format_adm( ctx, result.assumptions, small) posted = await ctx.send(embed=embed) try: await posted.add_reaction(DELETE_EMOJI) if not small and show_assuptions: await self.add_reaction_emoji(posted, result.assumptions) except discord.errors.NotFound: pass payload = { 'assumptions': result.assumptions.to_json(), 'query': query, 'used': False, 'blame': author.id, 'channel id': posted.channel.id, 'message id': posted.id, 'image ids': [i.id for i in messages], 'no change warning': False } await ctx.bot.keystore.set_json('wolfram', 'message', str(posted.id), payload, expire=60 * 60 * 24) print('Done.')
def test_friendly(): assert not is_bad('Hello, world!') assert not is_bad('THESE WORDS ARE FRIENDLY')
def test_malicious(): assert is_bad('CRAP') assert is_bad('oh f**k this') assert is_bad('This is shit.')
# Interactive command for checkig if a word is bad # This was written for testing purposes from wordfilter import is_bad line = input('> ') while line: if is_bad(line): print('That\'s bad!') else: print('All good!') line = input('> ')
def test_esoteric(): assert is_bad('\u200Bfuck') assert is_bad('sh\u200Bit')
async def answer_query(self, query, channel, blame, assumptions=[], debug=False): safe.sprint('wolfram|alpha :', blame.name, ':', query) await self.client.send_typing(channel) images = [] text = [] error = 0 error_message = 'No details' # Dummy message. This is a sign that I need to work on the settings module somewhat. class Dummy: def __init__(self, channel): self.channel = channel self.server = channel.server enable_filter = False if not channel.is_private: enable_filter = await core.settings.channel_get_setting( Dummy(channel), 'f-wolf-filter', 'nsfw' not in channel.name) # print(core.get_setting_context(Dummy(channel), 'f-wolf-filter', 'channel')) # print(core.get_setting_context(Dummy(channel), 'f-wolf-filter', 'server')) # print(enable_filter) if enable_filter and wordfilter.is_bad(query): await self.send_message(channel, FILTER_FAILURE, blame=blame) return try: print('Making request') result = await api.request(query, assumptions, debug=debug) print('Done?') except asyncio.TimeoutError: print('W|A timeout:', query) await self.send_message(channel, ERROR_MESSAGE_TIMEOUT.format(query), blame=blame) except aiohttp.ClientError as e: print('Wolf: HTTP processing error:', e.message) await self.send_message( channel, 'The server threw an error. Try again in a moment.', blame=blame) except xml.parsers.expat.ExpatError as e: print('Wolf: XML processing error:', e.message) await self.send_message( channel, 'The server returned some malformed data. Try again in a moment.', blame=blame) else: if len(result.sections) == 0: await self.send_message(channel, ERROR_MESSAGE_NO_RESULTS, blame=blame) elif result.did_fail: m = 'Something went wrong: {}'.format(result.error_text) await self.send_message(channel, m, blame=blame) else: # Get theme setting (TODO: Don't construct this myself) key = 'p-tex-colour:' + blame.id theme = await core.keystore.get(key) is_dark = (theme == 'dark') # print('The theme:', theme) # Send the image results background_colour = hex_to_tuple_a( '36393EFF') if is_dark else hex_to_tuple_a('FFFFFFFF') if not debug: strip = sections_to_image_strip(result.sections) strip = retheme_images( strip, image_recolour_to_dark_theme if is_dark else lambda x: None) for img in conjoin_image_results(strip, background_colour): img = paste_to_background(img, background_colour) # await self.send_image(channel, img, 'result.png', blame = blame) # if theme == 'dark': # image_recolour_to_dark_theme(img) await self.send_image(channel, img, 'result.png', blame=blame) await asyncio.sleep(1.05) # Text section textitems = [] # Assumptions assumption_text = self.get_assumption_text(result.assumptions) hidden_assumptions = assumption_text.count('\n') > 5 if hidden_assumptions: assumption_text = ASSUMPTIONS_MADE_MESSAGE textitems.append(assumption_text) # Tips if len(result.tips) > 0: textitems += ['**Tips**\n', '\n'.join(result.tips), '\n\n'] # Timeouts if len(result.timeouts) > 0: textitems += [ '**Timeouts**\n', ', '.join(result.timeouts), '\n\n' ] textout_joined = ''.join(textitems) url = urllib.parse.urlencode({'i': query}) # Determine if the footer should be long or short adm = FOOTER_MESSAGE.format(mention=blame.mention, query=url) if len(textout_joined) + len(adm) > 1950: adm = FOOTER_MESSAGE_SHORT.format(mention=blame.mention) # Send the result posted = await self.send_message(channel, textout_joined + adm, blame=blame) if result.assumptions.count - result.assumptions.count_unknown > 0: try: if hidden_assumptions: await self.client.add_reaction( posted, EXPAND_EMOJI) else: await self.add_reaction_emoji( posted, result.assumptions) payload = { 'assumptions': result.assumptions.to_json(), 'query': query, 'used': False, 'blame': blame.id, 'channel id': posted.channel.id, 'message id': posted.id, 'no change warning': False, 'hidden': hidden_assumptions } print(json.dumps(payload, indent=4)) # self.sent_footer_messages[str(posted.id)] = payload await core.keystore.set_json('wolfram', 'message', str(posted.id), payload, expire=60 * 60 * 24) print(self.shard_id, 'Footer message id:', posted.id) except discord.errors.Forbidden: await self.send_message(channel, REACTION_PERM_FAILURE, blame=blame) # Complete! print('Done.')
async def answer_query_short(self, query, channel, blame): safe.sprint('wolfram|alpha :', blame.name, ':', query) await self.client.send_typing(channel) images = [] text = [] error = 0 error_message = 'No details' # Dummy message. This is a sign that I need to work on the settings module somewhat. class Dummy: def __init__(self, channel): self.channel = channel self.server = channel.server enable_filter = False if not channel.is_private: enable_filter = await core.settings.channel_get_setting( Dummy(channel), 'f-wolf-filter', 'nsfw' not in channel.name) if enable_filter and wordfilter.is_bad(query): await self.send_message(channel, FILTER_FAILURE, blame=blame) return try: print('Making request') result = await api.request(query, [], debug=False) print('Done?') except asyncio.TimeoutError: print('W|A timeout:', query) await self.send_message(channel, ERROR_MESSAGE_TIMEOUT.format(query), blame=blame) except aiohttp.ClientError as e: print('Wolf: HTTP processing error:', e.message) await self.send_message( channel, 'The server threw an error. Try again in a moment.', blame=blame) except xml.parsers.expat.ExpatError as e: print('Wolf: XML processing error:', e.message) await self.send_message( channel, 'The server returned some malformed data. Try again in a moment.', blame=blame) else: # print(json.dumps(result.sections, indent = 4)) if len(result.sections) == 0: await self.send_message(channel, ERROR_MESSAGE_NO_RESULTS, blame=blame) elif result.did_fail: m = 'Something went wrong: {}'.format(result.error_text) await self.send_message(channel, m, blame=blame) else: # for i in result.sections: # print(' -', i.title) sections_reduced = list( cleanup_section_list( itertools.chain( [ find_first(section_is_input, result.sections, None) ], list(filter(section_is_important, result.sections)) or [ find_first(section_is_not_input, result.sections, None) ]))) is_dark = ((await core.keystore.get('p-tex-colour', blame.id)) == 'dark') # Send the image results background_colour = hex_to_tuple_a( '36393EFF' if is_dark else 'FFFFFFFF') strip = sections_to_image_strip(sections_reduced) if is_dark: strip = retheme_images(strip, image_recolour_to_dark_theme) else: strip = (i for i, _, _ in strip) for img in conjoin_image_results(strip, background_colour): img = paste_to_background(img, background_colour) await self.send_image(channel, img, 'result.png', blame=blame) await asyncio.sleep(1.05) # Text section url = urllib.parse.urlencode({'i': query}) adm = FOOTER_MESSAGE.format(mention=blame.mention, query=url) adm += '\n**This command is in development.** Suggest improvements on the MathBot server (type `=about` for the link).' posted = await self.send_message(channel, adm, blame=blame) print('Done.')
def test(): assert (not is_bad('Hello, world!')) assert (not is_bad('THESE WORDS ARE FRIENDLY')) assert (is_bad('CRAP')) assert (is_bad('oh f**k this')) assert (is_bad('This is shit.'))
async def answer_query(self, query, channel, blame, assumptions=[], small=False, debug=False): safe.sprint('wolfram|alpha :', blame.name, ':', query) await self.send_typing(channel) enable_filter = False if not channel.is_private: enable_filter = await core.settings.resolve('f-wolf-filter', channel, channel.server, default='nsfw' not in channel.name) if enable_filter and wordfilter.is_bad(query): await self.send_message(channel, FILTER_FAILURE, blame=blame) return try: print('Making request') units = await core.keystore.get('p-wolf-units:' + str(blame.id)) result = await api.request(query, assumptions, imperial=(units == 'imperial'), debug=debug) except (wolfapi.WolframError, wolfapi.WolframDidntSucceed): await self.send_message(channel, ERROR_MESSAGE_NO_RESULTS, blame=blame) except asyncio.TimeoutError: print('W|A timeout:', query) await self.send_message(channel, ERROR_MESSAGE_TIMEOUT.format(query), blame=blame) except aiohttp.ClientError as error: print('Wolf: HTTP processing error:', error.message) await self.send_message( channel, 'The server threw an error. Try again in a moment.', blame=blame) except xml.parsers.expat.ExpatError as error: print('Wolf: XML processing error:', error) await self.send_message( channel, 'The server returned some malformed data. Try again in a moment.', blame=blame) else: if len(result.sections) == 0: await self.send_message(channel, ERROR_MESSAGE_NO_RESULTS, blame=blame) return is_dark = (await core.keystore.get('p-tex-colour:' + blame.id)) == 'dark' sections_reduced = result.sections if not small else list( cleanup_section_list( itertools.chain( [find_first(section_is_input, result.sections, None)], list(filter(section_is_important, result.sections)) or [ find_first(section_is_not_input, result.sections, None) ]))) # Post images for img in process_images(sections_reduced, is_dark): await self.send_image(channel, img, 'result.png', blame=blame) await asyncio.sleep(1.05) embed, show_assuptions = await self.format_adm( channel, blame, query, result.assumptions, small) posted = await self.send_message(channel, embed=embed, blame=blame) if not small and show_assuptions: try: await self.add_reaction_emoji(posted, result.assumptions) payload = { 'assumptions': result.assumptions.to_json(), 'query': query, 'used': False, 'blame': blame.id, 'channel id': posted.channel.id, 'message id': posted.id, 'no change warning': False } await core.keystore.set_json('wolfram', 'message', str(posted.id), payload, expire=60 * 60 * 24) except discord.errors.Forbidden: await self.send_message(channel, REACTION_PERM_FAILURE, blame=blame) print('Done.')
async def answer_query(self, query, channel, blame, assumptions=[], small=False, debug=False): safe.sprint('wolfram|alpha :', blame.name, ':', query) await self.send_typing(channel) enable_filter = False if not channel.is_private: enable_filter = await core.settings.resolve('f-wolf-filter', channel, channel.server, default='nsfw' not in channel.name) if enable_filter and wordfilter.is_bad(query): await self.send_message(channel, FILTER_FAILURE, blame=blame) return try: print('Making request') result = await api.request(query, assumptions, debug=debug) except (wolfapi.WolframError, wolfapi.WolframDidntSucceed): await self.send_message(channel, ERROR_MESSAGE_NO_RESULTS, blame=blame) except asyncio.TimeoutError: print('W|A timeout:', query) await self.send_message(channel, ERROR_MESSAGE_TIMEOUT.format(query), blame=blame) except aiohttp.ClientError as error: print('Wolf: HTTP processing error:', error.message) await self.send_message( channel, 'The server threw an error. Try again in a moment.', blame=blame) except xml.parsers.expat.ExpatError as error: print('Wolf: XML processing error:', error) await self.send_message( channel, 'The server returned some malformed data. Try again in a moment.', blame=blame) else: if len(result.sections) == 0: await self.send_message(channel, ERROR_MESSAGE_NO_RESULTS, blame=blame) return is_dark = (await core.keystore.get('p-tex-colour:' + blame.id)) == 'dark' sections_reduced = result.sections if not small else list( cleanup_section_list( itertools.chain( [find_first(section_is_input, result.sections, None)], list(filter(section_is_important, result.sections)) or [ find_first(section_is_not_input, result.sections, None) ]))) # Post images for img in process_images(sections_reduced, is_dark): await self.send_image(channel, img, 'result.png', blame=blame) await asyncio.sleep(1.05) # Assumptions assumption_text = '' if not small: assumption_text = self.get_assumption_text(result.assumptions) hidden_assumptions = assumption_text.count('\n') > 5 if hidden_assumptions: assumption_text = ASSUMPTIONS_MADE_MESSAGE url = urllib.parse.urlencode({'i': query}) # Determine if the footer should be long or short adm = await self.format_adm(channel, blame, query, small) output = assumption_text + adm too_long = False if len(output) >= 2000: too_long = True output = adm # Send the result posted = await self.send_message(channel, output, blame=blame) if not small and result.assumptions.count_known > 0 and not too_long: try: if hidden_assumptions: await self.client.add_reaction(posted, EXPAND_EMOJI) else: await self.add_reaction_emoji(posted, result.assumptions) payload = { 'assumptions': result.assumptions.to_json(), 'query': query, 'used': False, 'blame': blame.id, 'channel id': posted.channel.id, 'message id': posted.id, 'no change warning': False, 'hidden': hidden_assumptions } # print(json.dumps(payload, indent=4)) # self.sent_footer_messages[str(posted.id)] = payload await core.keystore.set_json('wolfram', 'message', str(posted.id), payload, expire=60 * 60 * 24) # print(self.shard_id, 'Footer message id:', posted.id) except discord.errors.Forbidden: await self.send_message(channel, REACTION_PERM_FAILURE, blame=blame) print('Done.')