Skip to content
This repository was archived by the owner on Mar 14, 2021. It is now read-only.

Commit 3b22c61

Browse files
committed
Input validation
1 parent 60ea12a commit 3b22c61

File tree

2 files changed

+84
-20
lines changed

2 files changed

+84
-20
lines changed

bot/cogs/snakes.py

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@
1010
from discord.ext import commands
1111
from discord.ext.commands import Context
1212

13+
from ..hardcodings import categories
14+
1315
log = logging.getLogger(__name__)
1416

15-
API = 'http://en.wikipedia.org/w/api.php?format=json&redirects=1&action='
17+
API = 'https://en.wikipedia.org/w/api.php?format=json&redirects=1&action='
1618
rSENTENCE = re.compile(r'^.+?\.')
1719
rBRACK = re.compile(r'[[(].+?[\])]')
20+
rMDLINK = re.compile(r'(\[.*?\])\((\S+?)\s".*?"\)')
1821

1922

2023
class Snakes:
@@ -26,9 +29,18 @@ def __init__(self, bot: commands.AutoShardedBot):
2629
self.bot = bot
2730
self.session = aiohttp.ClientSession(loop=bot.loop) # the provided session says no host is reachable
2831
self.h2md = html2text.HTML2Text() # TODO: use
29-
self.base_query = API + 'parse&prop=text&page={}'
30-
self.secs_query = API + 'parse&prop=sections&page={}'
31-
self.img_query = API + 'query&titles={}&prop=pageimages&pithumbsize=300'
32+
self.base_query = API + (
33+
'parse'
34+
'&page={}'
35+
'&prop=text|sections'
36+
)
37+
self.info_query = API + (
38+
'query'
39+
'&titles={}'
40+
'&prop=pageimages|categories'
41+
'&pithumbsize=300'
42+
f'&cllimit=max&clcategories={categories}'
43+
)
3244

3345
async def get_snek(self, name: str = None) -> Dict[str, Any]:
3446
"""
@@ -45,27 +57,33 @@ async def get_snek(self, name: str = None) -> Dict[str, Any]:
4557
"""
4658
# TODO: Random will be done by fetching from Special:RandomInCategory/Venomous_snakes, or something
4759
async with self.session.get(self.base_query.format(name)) as pg_resp, \
48-
self.session.get(self.secs_query.format(name)) as sc_resp, \
49-
self.session.get(self.img_query.format(name)) as img_resp: # noqa
60+
self.session.get(self.info_query.format(name)) as if_resp: # noqa
5061
data = await pg_resp.json()
51-
secs = await sc_resp.json()
52-
img = await img_resp.json()
62+
info = await if_resp.json()
63+
64+
pg_id = str(data['parse']['pageid'])
65+
pg_info = info['query']['pages'][pg_id]
66+
if 'categories' not in pg_info:
67+
raise ValueError("This doesn't appear to be a snake!")
5368
soup = bs4.BeautifulSoup(data['parse']['text']['*'])
5469
tidbits = []
55-
for section in secs['parse']['sections']:
70+
for section in data['parse']['sections']:
71+
if sum(map(len, tidbits)) > 1500:
72+
break
5673
tag = rBRACK.sub('', str(soup.find(id=section['anchor']).find_next('p')))
5774
try:
58-
tidbits.append(self.h2md.handle(rSENTENCE.match(tag).group()).replace('\n', ' '))
75+
tidbit = self.h2md.handle(rSENTENCE.match(tag).group()).replace('\n', ' ')
5976
except AttributeError:
6077
pass
61-
if sum(map(len, tidbits)) > 1500:
62-
break
78+
else:
79+
tidbits.append(rMDLINK.sub(lambda m: f'{m[1]}(https://en.wikipedia.org{m[2]})', tidbit))
6380
try:
64-
pg_id = str(data['parse']['pageid'])
65-
imglink = img['query']['pages'][pg_id]['thumbnail']['source']
81+
img_url = pg_info['thumbnail']['source']
6682
except KeyError:
67-
imglink = None
68-
return {'image': imglink, 'tidbits': tidbits}
83+
img_url = None
84+
title = data['parse']['title']
85+
pg_url = f'https://en.wikipedia.org/wiki/{title.replace(" ", "_")}'
86+
return {'info': (img_url, pg_url, title), 'tidbits': tidbits}
6987

7088
@commands.command()
7189
async def get(self, ctx: Context, name: str = None):
@@ -78,10 +96,14 @@ async def get(self, ctx: Context, name: str = None):
7896
:param ctx: Context object passed from discord.py
7997
:param name: Optional, the name of the snake to get information for - omit for a random snake
8098
"""
81-
d = await self.get_snek(name)
82-
embed = discord.Embed(description='\n\n • '.join(d['tidbits']))
83-
if d['image'] is not None:
84-
embed.set_thumbnail(url=d['image'])
99+
try:
100+
snek = await self.get_snek(name)
101+
except ValueError as e:
102+
return await ctx.send(f'`{e}`')
103+
image, page, title = snek['info']
104+
embed = discord.Embed(title=title, url=page, description='\n\n • '.join(snek['tidbits']))
105+
if image is not None:
106+
embed.set_thumbnail(url=image)
85107
await ctx.send(embed=embed)
86108

87109

bot/hardcodings.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#encoding: utf-8
2+
3+
categories = '|'.join(
4+
f'Category:{s}' for s in [
5+
'Acrochordidae',
6+
'Alethinophidia',
7+
'Aniliidae',
8+
'Anomalepidae',
9+
'Anomochilidae',
10+
'Boidae',
11+
'Bolyeriidae',
12+
'Colubrids',
13+
'Colubrid_stubs',
14+
'Crotalinae',
15+
'Crotalis',
16+
'Cylindrophiidae',
17+
'Elapidae',
18+
'Gerrhopilidae',
19+
'Homalopsidae',
20+
'Lamprophiidae',
21+
'Leptotyphlopidae',
22+
'Loxocemidae',
23+
'Mambas',
24+
'Pareidae',
25+
'Pythonidae',
26+
'Snakes',
27+
'Snake_families',
28+
'Snake_genera',
29+
'Snake_stubs',
30+
'Thamnophis',
31+
'Tropidophiidae',
32+
'Typhlopidae',
33+
'Uropeltidae',
34+
'Venomous_snakes',
35+
'Viperidae',
36+
'Viperinae',
37+
'Xenodermidae',
38+
'Xenopeltidae',
39+
'Xenophidiidae',
40+
'Xenotyphlopidae',
41+
]
42+
)

0 commit comments

Comments
 (0)