198 lines
6.2 KiB
Python
198 lines
6.2 KiB
Python
import json
|
||
import re
|
||
from types import SimpleNamespace
|
||
from actions.file.file_name_generator import FileNameGenerator
|
||
from actions.file.json_file_saver import JsonFileSaver
|
||
import httpx
|
||
from actions.data.dict_to_obj import DictToObj
|
||
from actions.ui.ui import fail, ok, rule
|
||
|
||
|
||
class ApiAction:
|
||
|
||
def __init__(self) -> None:
|
||
|
||
self.file_name_generator = FileNameGenerator()
|
||
|
||
# Classe para obter as variaveis de ambiente
|
||
mirror_sync_env = SimpleNamespace(
|
||
url="https://mattermost.oriustecnologia.com/api/v4/",
|
||
timeout=10,
|
||
token="uzszwh6c7pbc8xyt1d1skope8y",
|
||
)
|
||
|
||
# Obtem as variaveis de ambiente em formato de objeto
|
||
self.mirror_sync_env = mirror_sync_env
|
||
|
||
pass
|
||
|
||
def sanitize_unicode(self, data):
|
||
"""
|
||
Remove caracteres inválidos (surrogates) de strings dentro de estruturas complexas.
|
||
"""
|
||
if isinstance(data, str):
|
||
# Remove caracteres Unicode no intervalo D800–DFFF (não permitidos em UTF-8)
|
||
return re.sub(r"[\ud800-\udfff]", "", data)
|
||
elif isinstance(data, list):
|
||
return [self.sanitize_unicode(i) for i in data]
|
||
elif isinstance(data, dict):
|
||
return {k: self.sanitize_unicode(v) for k, v in data.items()}
|
||
return data
|
||
|
||
# Cria os Cabeçalhos de envio
|
||
def _headers(self, data):
|
||
|
||
headers = {
|
||
"Accept": getattr(data, "accept", "application/json"),
|
||
"Content-Type": getattr(data, "content_type", "application/json"),
|
||
}
|
||
|
||
token = getattr(data, "token", None)
|
||
|
||
if token:
|
||
headers["Authorization"] = f"Bearer {token}"
|
||
|
||
return headers
|
||
|
||
# Trata os dados da respsota
|
||
async def _response(self, response: httpx.Response, data):
|
||
|
||
# Tenta JSON; se falhar, retorna texto bruto
|
||
try:
|
||
|
||
# Gerador de arquivo JSON
|
||
json_file_saver = JsonFileSaver()
|
||
|
||
# Obtem o código de requisição
|
||
status = response.status_code
|
||
|
||
# Converter o Json para objeto
|
||
response = DictToObj(response.json())
|
||
|
||
# Verifica o tipo de resposta
|
||
match status:
|
||
|
||
case 200:
|
||
rule("Dados enviados.:" + str(status))
|
||
ok("Verifique o log...")
|
||
json_file_saver.save(
|
||
response,
|
||
"storage/2XX/"
|
||
+ self.file_name_generator.generate("200")
|
||
+ ".json",
|
||
)
|
||
|
||
case 201:
|
||
rule("Dados criados.:" + str(status))
|
||
ok("Verifique o log...")
|
||
json_file_saver.save(
|
||
response,
|
||
"storage/2XX/"
|
||
+ self.file_name_generator.generate("201")
|
||
+ ".json",
|
||
)
|
||
|
||
case 400:
|
||
rule("Error.:" + str(status))
|
||
fail("Verifique o log...")
|
||
json_file_saver.save(
|
||
response,
|
||
"storage/4XX/"
|
||
+ self.file_name_generator.generate("400")
|
||
+ ".json",
|
||
)
|
||
|
||
case 404:
|
||
rule("Error.:" + str(status))
|
||
fail("Verifique o log...")
|
||
json_file_saver.save(
|
||
response,
|
||
"storage/4XX/"
|
||
+ self.file_name_generator.generate("404")
|
||
+ ".json",
|
||
)
|
||
|
||
case 422:
|
||
rule("Error.:" + str(status))
|
||
fail("Verifique o log....")
|
||
json_file_saver.save(
|
||
response,
|
||
"storage/4XX/"
|
||
+ self.file_name_generator.generate("422")
|
||
+ ".json",
|
||
)
|
||
|
||
return response
|
||
|
||
except ValueError:
|
||
|
||
return DictToObj(
|
||
{
|
||
"status": status,
|
||
"message": json.dumps(response, ensure_ascii=False, default=vars),
|
||
"data": None,
|
||
}
|
||
)
|
||
|
||
# Contrói a requisição
|
||
async def _request(self, client: httpx.AsyncClient, data):
|
||
"""
|
||
Constrói e envia a requisição com base no método HTTP definido em `data.method`.
|
||
|
||
Suporta:
|
||
- GET: usa params (query string)
|
||
- POST/PUT/PATCH: usa json ou form (data)
|
||
- DELETE: suporta params opcionais
|
||
"""
|
||
# Obtem o verbo de requisição
|
||
method = data.method.lower().strip()
|
||
|
||
# Obtem o endpoint
|
||
url = data.endpoint.lstrip("/")
|
||
|
||
# Prepara argumentos de envio
|
||
kwargs = {}
|
||
|
||
# Obtem o corpo da requisição
|
||
body = getattr(data, "body", None)
|
||
|
||
# Corpo JSON ou formulário (para POST/PUT/PATCH)
|
||
if body is not None:
|
||
|
||
# Sanitiza caracteres inválidos antes de enviar
|
||
body = self.sanitize_unicode(body)
|
||
|
||
# Guarda o corpo da requisição
|
||
kwargs["json"] = body
|
||
|
||
# Constrói o request (sem enviar ainda)
|
||
request = client.build_request(method.upper(), url, **kwargs)
|
||
|
||
# Envia a requisição (client.send respeita timeout e intercepta tudo)
|
||
response = await client.send(request)
|
||
|
||
# Se sucesso, trata normalmente
|
||
return await self._response(response, data)
|
||
|
||
# Prepara os dados para envio
|
||
async def send(self, data):
|
||
|
||
async with httpx.AsyncClient(
|
||
base_url=self.mirror_sync_env.url,
|
||
headers=self._headers(data),
|
||
timeout=getattr(data, "timeout", int(self.mirror_sync_env.timeout)),
|
||
follow_redirects=True,
|
||
) as client:
|
||
|
||
rule("Salvando Dados de Envio...")
|
||
if True:
|
||
json_file_saver = JsonFileSaver()
|
||
json_file_saver.save(
|
||
data,
|
||
"storage/data/" + self.file_name_generator.generate() + ".json",
|
||
)
|
||
|
||
response = await self._request(client, data)
|
||
|
||
# Pydantic v2 valida e ignora campos extras (ex.: userId)
|
||
return response
|