Closed mbdaso closed 5 years ago
https://github.com/aplatanado/slack-badges-bot/pull/11/commits/e8960f04b4c7c4f9e3d0d77e67c84cb5774d47cc Corregidos fallos en verificación
Al principio tuve un problema con la peticion que llega desde slack al servidor en
async def slash_command_handler(self, request): # TODO: Comprobar argumentos en request y añadir manejo de errores y excepciones # TODO: Usar signed secrets para comprobar que quien hace la petición es Slack. # Ver https://api.slack.com/docs/verifying-requests-from-slack try: request.query['text']
request.query['text'] produce "KeyError: 'text'"
Ok. No necesitas esa función. Te explico el error.
Slack te hace a ti una petición HTTP para pasarte los datos. En ese sentido el servidor de Slack hace de cliente tu de navegador. Para tratar la petición hay que mirar la documentación porque hay distintos tipos de peticiones y según el tipo hay varias formas de pasar parámetros.
Todos los tipos admiten mandar información en el cuerpo de la petición. Así que por ahí se mueden mandar los parámetros codificados como se prefiera. Está de moda usar JSON pero podría ser XML, texto plano o un formato que inventes. En resumen, un petición GET se manda así por la red.
GET /index.html HTTP/1.1
Host: www.example.com
Referer: www.google.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0
Connection: keep-alive
[Línea en blanco]
{
"id": "hola",
"text": "hoaoalala"
}
Y lo mismo pasa con peticiones POST, DELETE, UPDATE y otras.
Pero esta no la única forma de pasar parámetros. Otra forma es en a URL. Simplemente se añade a la URL ? seguido de los parámetros separados por &. Así una petición a:
http://www.example.com/index.html?opcion1=foo&opcion2=bar
Se convierte en una petición así:
GET /index.htmll?opcion1=foo&opcion2=bar HTTP/1.1
Host: www.example.com
Referer: www.google.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0
Connection: keep-alive
[Línea en blanco]
Eso es lo que suelen hacer los navegadores cuando pones una URL y le das a enter. Ahora bien, si la petición se crea con código, usando una librería como requests, la petición puede tener cuerpo y parámetros en la query:
GET /index.htmll?opcion1=foo&opcion2=bar HTTP/1.1
Host: www.example.com
Referer: www.google.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0
Connection: keep-alive
[Línea en blanco]
{
"id": "hola",
"text": "hoaoalala"
}
Y ahi está la cosa. En el request de AIOHttp query es un diccionario con los parámetros de la URL:
https://docs.aiohttp.org/en/stable/web_reference.html#aiohttp.web.BaseRequest.query
Mientras que read() sirve para leer el body (si existe).
https://docs.aiohttp.org/en/stable/web_reference.html#aiohttp.web.BaseRequest.read
Claro, slack no te pasa text por la URL sino por el cuerpo. No necesitas esa función que has hecho porque si miras un poco más abajo verás que request tiene el método json():
https://docs.aiohttp.org/en/stable/web_reference.html#aiohttp.web.BaseRequest.json
Que lee el cuerpo y lo decodifica considerando es un JSON.
De resto, todo bien. Así se ve en slack:
Está chulo :)
Tampoco funciona con json()
Traceback (most recent call last):
File "/home/mbelda/repos/slack-badges-bot/slack_badges_bot/adapters/slack.py", line 76, in slash_command_handler
request_json = await request.json()
File "/home/mbelda/.local/share/virtualenvs/slack-badges-bot-5-YPmOZL/lib/python3.7/site-packages/aiohttp/web_request.py", line 584, in json
return loads(body)
File "/usr/lib/python3.7/json/__init__.py", line 348, in loads
return _default_decoder.decode(s)
File "/usr/lib/python3.7/json/decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/usr/lib/python3.7/json/decoder.py", line 355, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
Este es el paquete que manda slack:
POST /slack/slash-command HTTP/1.0
Host: localhost:5000
Connection: close
Content-Length: 365
User-Agent: Slackbot 1.0 (+https://api.slack.com/robots)
Accept-Encoding: gzip,deflate
Accept: application/json,*/*
X-Slack-Signature: v0=d0c98b410ef172e5c774aa1c3647b01dc23b8ff894d7ffc73a27f2611b071a22
X-Slack-Request-Timestamp: 1565308514
Content-Type: application/x-www-form-urlencoded
Cache-Control: max-age=259200
token=41S425kCtbTlfDvhNhbkRyCL&team_id=TJ4FFFPQC&team_domain=ullespacio&channel_id=CJ4FFG21J&channel_name=general&user_id=UHYNH5UL9&user_name=alu0100832211&command=%2Fbadges&text=list+all&response_url=https%3A%2F%2Fhooks.slack.com%2Fcommands%2FTJ4FFFPQC%2F721129123488%2FAhjK0m1F4WWOQTQeEo3furdu&trigger_id=722999692167.616525533828.511ae45d3cfeecc1bdfb44a7820d4c29%
Vale. Es que lo llamaste request_json pero no era un json. Es el formato típico con el que se mandan los formularios con un post. Se llaman application/x-www-form-urlencoded y es similar a la query en la URL.
Usa https://docs.aiohttp.org/en/stable/web_reference.html#aiohttp.web.BaseRequest.post
Ahora sí
Al principio tuve un problema con la peticion que llega desde slack al servidor en
request.query['text'] produce "KeyError: 'text'" Así que escribí un método para pasarlo todo a json con urllib:
De resto, todo bien. Así se ve en slack: