csc-cia-stne 0.0.37__py3-none-any.whl → 0.0.39__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- csc_cia_stne/__init__.py +5 -1
- csc_cia_stne/google_drive.py +50 -47
- csc_cia_stne/provio.py +1 -1
- csc_cia_stne/servicenow.py +197 -231
- csc_cia_stne/slack.py +227 -0
- csc_cia_stne/utilitarios/validations/GoogleDriveValidator.py +30 -5
- csc_cia_stne/utilitarios/validations/ServiceNowValidator.py +47 -11
- csc_cia_stne/utilitarios/validations/__init__.py +2 -1
- {csc_cia_stne-0.0.37.dist-info → csc_cia_stne-0.0.39.dist-info}/METADATA +3 -1
- {csc_cia_stne-0.0.37.dist-info → csc_cia_stne-0.0.39.dist-info}/RECORD +13 -12
- {csc_cia_stne-0.0.37.dist-info → csc_cia_stne-0.0.39.dist-info}/WHEEL +1 -1
- {csc_cia_stne-0.0.37.dist-info → csc_cia_stne-0.0.39.dist-info}/LICENCE +0 -0
- {csc_cia_stne-0.0.37.dist-info → csc_cia_stne-0.0.39.dist-info}/top_level.txt +0 -0
csc_cia_stne/servicenow.py
CHANGED
@@ -3,7 +3,7 @@ import base64, json
|
|
3
3
|
import os
|
4
4
|
import logging
|
5
5
|
from pydantic import ValidationError
|
6
|
-
from .utilitarios.validations.ServiceNowValidator import
|
6
|
+
from .utilitarios.validations.ServiceNowValidator import *
|
7
7
|
|
8
8
|
class ServiceNow:
|
9
9
|
|
@@ -27,14 +27,10 @@ class ServiceNow:
|
|
27
27
|
api_header (dict): Cabeçalhos padrão para requisições API.
|
28
28
|
"""
|
29
29
|
try:
|
30
|
-
InitParamsValidator(username=username, password=password, env=env
|
30
|
+
InitParamsValidator(username=username, password=password, env=env )
|
31
31
|
except ValidationError as e:
|
32
32
|
raise ValueError("Erro na validação dos dados de input da inicialização da instância 'ServiceNow':", e.errors())
|
33
|
-
|
34
|
-
# Verifica se todos os parâmetros foram fornecidos e não estão vazios
|
35
|
-
if not all([username and username.strip(), password and password.strip(), env and env.strip()]):
|
36
|
-
raise ValueError("Todos os parâmetros precisam ser fornecidos para a criação da instância ServiceNow, ou algum dos valores esta nulo ou vazio (username, password, env)")
|
37
|
-
|
33
|
+
|
38
34
|
# Normaliza o valor de 'env' para maiúsculas
|
39
35
|
env = env.strip().upper()
|
40
36
|
|
@@ -51,22 +47,21 @@ class ServiceNow:
|
|
51
47
|
raise ValueError("O valor de 'env' precisa ser 'dev', 'qa', 'qas' ou 'prod'.")
|
52
48
|
|
53
49
|
# Atribui as variáveis de instância
|
54
|
-
self.
|
55
|
-
self.
|
50
|
+
self.__username = username.strip()
|
51
|
+
self.__password = password.strip()
|
56
52
|
self.env = env
|
57
53
|
self.api_url = valid_envs[env]
|
58
54
|
self.api_header = {"Content-Type":"application/json","Accept":"application/json"}
|
59
55
|
|
60
|
-
# Criação de funções básicas para reutilizar nas funções especificas
|
61
56
|
|
62
57
|
def __auth(self):
|
63
58
|
"""
|
64
59
|
Retorna o e-mail e senha para realizar a autenticação.
|
65
60
|
"""
|
66
|
-
return (self.
|
61
|
+
return (self.__username, self.__password)
|
67
62
|
|
68
63
|
|
69
|
-
def request (self, url : str , params : str = "",
|
64
|
+
def request (self, url : str , params : str = "", timeout : int = 15):
|
70
65
|
"""
|
71
66
|
Realiza uma requisição GET para a URL especificada.
|
72
67
|
|
@@ -96,7 +91,7 @@ class ServiceNow:
|
|
96
91
|
- Verifica o certificado SSL (`verify=True`).
|
97
92
|
"""
|
98
93
|
try:
|
99
|
-
RequestValidator(url=url, params=params, timeout=
|
94
|
+
RequestValidator(url=url, params=params, timeout=timeout)
|
100
95
|
except ValidationError as e:
|
101
96
|
raise ValueError("Erro na validação dos dados de input do método:", e.errors())
|
102
97
|
|
@@ -106,7 +101,7 @@ class ServiceNow:
|
|
106
101
|
params=params,
|
107
102
|
auth=self.__auth(),
|
108
103
|
headers=self.api_header,
|
109
|
-
timeout=
|
104
|
+
timeout=timeout,
|
110
105
|
verify=True
|
111
106
|
)
|
112
107
|
|
@@ -116,7 +111,7 @@ class ServiceNow:
|
|
116
111
|
# Analisa o conteúdo da resposta JSON
|
117
112
|
result = response.json()
|
118
113
|
if "result" in result:
|
119
|
-
return {"success" : True, "result" : result}
|
114
|
+
return {"success" : True, "result" : result.get("result")}
|
120
115
|
else:
|
121
116
|
logging.debug("A resposta não contém o campo 'result'.")
|
122
117
|
return {"success" : False, "result" : result}
|
@@ -134,6 +129,67 @@ class ServiceNow:
|
|
134
129
|
return {"success" : False, "result" : None, "error" : str(e)}
|
135
130
|
|
136
131
|
|
132
|
+
def __request_download(self, url, params = "", timeout = 15):
|
133
|
+
"""
|
134
|
+
Realiza uma requisição GET para a URL especificada.
|
135
|
+
|
136
|
+
Parâmetros:
|
137
|
+
url (str): URL para a qual a requisição será enviada.
|
138
|
+
params (dict, opcional): Parâmetros de consulta (query parameters) a serem incluídos na requisição.
|
139
|
+
Padrão é uma string vazia.
|
140
|
+
|
141
|
+
Retorno:
|
142
|
+
dict: Um dicionário contendo:
|
143
|
+
- success (bool): Indica se a requisição foi bem-sucedida.
|
144
|
+
- result (dict ou None): Resultado da resposta, se disponível. Contém o conteúdo JSON do campo "result".
|
145
|
+
- error (Exception ou None): Objeto de exceção em caso de erro, ou None se não houver erros.
|
146
|
+
|
147
|
+
Tratamento de exceções:
|
148
|
+
- requests.exceptions.HTTPError: Lança um erro HTTP caso o código de status indique falha.
|
149
|
+
- requests.exceptions.RequestException: Captura outros erros relacionados à requisição, como timeout ou conexão.
|
150
|
+
- Exception: Captura erros inesperados.
|
151
|
+
|
152
|
+
Logs:
|
153
|
+
- Logs de depuração são gerados para erros HTTP, erros de requisição e exceções inesperadas.
|
154
|
+
- Um aviso é registrado caso a resposta não contenha o campo "result".
|
155
|
+
|
156
|
+
Observações:
|
157
|
+
- Utiliza autenticação fornecida pelo método privado `__auth()`.
|
158
|
+
- Define um tempo limite (`timeout`) de 15 segundos.
|
159
|
+
- Verifica o certificado SSL (`verify=True`).
|
160
|
+
"""
|
161
|
+
try:
|
162
|
+
response = requests.get(
|
163
|
+
url,
|
164
|
+
params=params,
|
165
|
+
auth=self.__auth(),
|
166
|
+
headers=self.api_header,
|
167
|
+
timeout=timeout,
|
168
|
+
verify=True
|
169
|
+
)
|
170
|
+
|
171
|
+
# VALIDA SE HOUVE SUCESSO NA REQUISIÇÃO
|
172
|
+
response.raise_for_status()
|
173
|
+
# Analisa o conteúdo da resposta JSON
|
174
|
+
if response.status_code == 200:
|
175
|
+
return {"success" : True, "result" : response}
|
176
|
+
else:
|
177
|
+
logging.debug("Erro ao realizar a consulta")
|
178
|
+
return {"success" : False, "result" : response.status_code}
|
179
|
+
|
180
|
+
except requests.exceptions.HTTPError as http_err:
|
181
|
+
logging.debug(f"Erro HTTP ao buscar os detalhes do ticket: {http_err}")
|
182
|
+
return {"success" : False, "error" : str(http_err), "result" : None}
|
183
|
+
|
184
|
+
except requests.exceptions.RequestException as req_err:
|
185
|
+
logging.debug(f"Erro ao buscar os detalhes do ticket: {req_err}")
|
186
|
+
return {"success" : False, "error" : str(req_err), "result" : None}
|
187
|
+
|
188
|
+
except Exception as e:
|
189
|
+
logging.debug(f"Erro inesperado: {e}")
|
190
|
+
return {"success" : False, "error" : str(e), "result" : None}
|
191
|
+
|
192
|
+
|
137
193
|
def put(self, url, payload, timeout = 15):
|
138
194
|
"""
|
139
195
|
Realiza uma requisição PUT para a URL especificada.
|
@@ -272,7 +328,7 @@ class ServiceNow:
|
|
272
328
|
return {"success" : False, "error" : str(e) , "result" : None}
|
273
329
|
|
274
330
|
|
275
|
-
def listar_tickets(self, tabela: str = None, campos: list = None, query: str = None, limite: int = 50, timeout:int=15)->dict:
|
331
|
+
def listar_tickets(self, tabela: str = None, campos: list = None, query: str = None, limite: int = 50, timeout:int=15, sysparm_display_value: str = "")->dict:
|
276
332
|
"""lista tickets do ServiceNow
|
277
333
|
|
278
334
|
Args:
|
@@ -290,46 +346,23 @@ class ServiceNow:
|
|
290
346
|
except ValidationError as e:
|
291
347
|
raise ValueError("Erro na validação dos dados de input do método:", e.errors())
|
292
348
|
|
293
|
-
# # Validação de 'tabela'
|
294
|
-
# if not tabela or not tabela.strip():
|
295
|
-
# raise ValueError("O parâmetro 'tabela' precisa ser especificado com o nome da tabela de onde os tickets serão listados.")
|
296
|
-
|
297
|
-
# # Validação de 'campos'
|
298
|
-
# if not isinstance(campos, list) or not campos or not all(isinstance(campo, str) and campo.strip() for campo in campos):
|
299
|
-
# raise ValueError("O parâmetro 'campos' precisa ser uma lista não vazia de strings válidas com os nomes dos campos do formulário.")
|
300
|
-
|
301
|
-
# # Validação de 'query'
|
302
|
-
# if not query or not query.strip():
|
303
|
-
# raise ValueError("O parâmetro 'query' precisa ser uma string não vazia.")
|
304
|
-
|
305
|
-
# # Validação de 'timeout'
|
306
|
-
# if not isinstance(timeout, int):
|
307
|
-
# raise ValueError("O parâmetro 'timeout' precisa ser um valor (int) em segundos.")
|
308
|
-
|
309
|
-
# # Validação de 'limite'
|
310
|
-
# if not isinstance(limite, int):
|
311
|
-
# raise ValueError("O parâmetro 'limite' precisa ser um número inteiro.")
|
312
349
|
|
313
350
|
params = {
|
314
351
|
"sysparm_query" : query,
|
315
352
|
"sysparm_fields" : ','.join(campos),
|
316
|
-
"sysparm_display_value" :
|
353
|
+
"sysparm_display_value" : sysparm_display_value,
|
317
354
|
"sysparm_limit" : limite
|
318
355
|
}
|
319
|
-
# params["sysparm_query"] = query
|
320
|
-
# params["sysparm_fields"] = ','.join(campos)
|
321
|
-
# params["sysparm_display_value"] = "all"
|
322
|
-
# params["sysparm_limit"] = limite
|
323
356
|
|
324
357
|
url = f"{self.api_url}/now/table/{tabela}"
|
325
358
|
|
326
359
|
try:
|
327
|
-
response = self.request(url=url, params=params,
|
328
|
-
|
329
|
-
return {"success":True, "result": response.json()}
|
360
|
+
response = self.request(url=url, params=params, timeout=timeout)
|
361
|
+
return response
|
330
362
|
|
331
363
|
except Exception as e:
|
332
|
-
|
364
|
+
logging.debug(f"erro: {e}")
|
365
|
+
return str(e)
|
333
366
|
|
334
367
|
|
335
368
|
def update_ticket(self, tabela: str = None, sys_id: str = None, payload: dict = None, timeout:int=15)->dict:
|
@@ -348,32 +381,17 @@ class ServiceNow:
|
|
348
381
|
UpdateTicketValidator(tabela=tabela, sys_id=sys_id, payload=payload, timeout=timeout)
|
349
382
|
except ValidationError as e:
|
350
383
|
raise ValueError("Erro na validação dos dados de input do método:", e.errors())
|
351
|
-
|
352
|
-
|
353
|
-
# if not tabela or not tabela.strip():
|
354
|
-
# raise ValueError("O parâmetro 'tabela' precisa ser especificado com o nome da tabela de onde o ticket será atualizado.")
|
355
|
-
|
356
|
-
# # Validação de 'sys_id'
|
357
|
-
# if not sys_id or not sys_id.strip():
|
358
|
-
# raise ValueError("O parâmetro 'sys_id' precisa ser especificado com o sys_id do ticket.")
|
359
|
-
|
360
|
-
# # Validação de 'payload'
|
361
|
-
# if not isinstance(payload, dict):
|
362
|
-
# raise ValueError("O parâmetro 'campos' precisa ser um dicionário contendo os campos do ticket a serem atualizados.")
|
363
|
-
|
364
|
-
if "assigned_to" not in payload:
|
365
|
-
|
366
|
-
payload["assigned_to"] = self.username
|
384
|
+
|
385
|
+
payload["assigned_to"] = self.__username
|
367
386
|
|
368
387
|
try:
|
369
388
|
|
370
389
|
url = f"{self.api_url}/now/table/{tabela}/{sys_id}"
|
371
390
|
response = self.put(url, payload=payload, timeout=timeout)
|
372
|
-
|
373
|
-
return {"success" : True, "result" : response.json() , "error" : None}
|
391
|
+
return response
|
374
392
|
|
375
393
|
except Exception as e:
|
376
|
-
return
|
394
|
+
return str(e)
|
377
395
|
|
378
396
|
|
379
397
|
def anexar_arquivo_no_ticket(self,header_content_type:dict=None, anexo_path:str=None, tabela:str=None, sys_id:str=None, timeout:int=15):
|
@@ -389,55 +407,40 @@ class ServiceNow:
|
|
389
407
|
Returns:
|
390
408
|
dict: resposta do ServiceNow
|
391
409
|
"""
|
410
|
+
if header_content_type is None:
|
411
|
+
header_content_type = self.__valida_header_content_type(anexo_path, header_content_type)
|
412
|
+
|
392
413
|
try:
|
393
414
|
AttachFileTicketValidator(header_content_type=header_content_type, anexo_path=anexo_path, tabela=tabela, sys_id=sys_id, timeout=timeout)
|
394
415
|
except ValidationError as e:
|
395
416
|
raise ValueError("Erro na validação dos dados de input do método:", e.errors())
|
396
417
|
|
397
|
-
# # Validação de 'tabela'
|
398
|
-
# if not tabela or not tabela.strip():
|
399
|
-
# raise ValueError("O parâmetro 'tabela' precisa ser especificado com o nome da tabela do ticket pra onde o arquivo será anexado.")
|
400
|
-
|
401
|
-
# # Validação de 'sys_id'
|
402
|
-
# if not sys_id or not sys_id.strip():
|
403
|
-
# raise ValueError("O parâmetro 'sys_id' precisa ser especificado com o sys_id do ticket que o arquivo será anexado.")
|
404
|
-
|
405
|
-
# # Validação de 'anexo_path'
|
406
|
-
# if not anexo_path or not anexo_path.strip():
|
407
|
-
# raise ValueError("O parâmetro 'anexo_path' precisa ser especificado com o path para o arquivo a ser anexado.")
|
408
|
-
|
409
418
|
if not os.path.exists(anexo_path):
|
410
419
|
raise FileExistsError(f"O arquivo não foi encontrado ({anexo_path})")
|
411
420
|
|
412
|
-
|
421
|
+
|
413
422
|
|
414
423
|
# Converte as chaves do dicionário para minúsculas
|
415
424
|
header_content_type_lower = {k.lower(): v for k, v in header_content_type.items()}
|
416
425
|
|
417
426
|
|
418
|
-
|
419
427
|
if "content-type" not in header_content_type_lower:
|
420
|
-
|
421
428
|
raise ValueError("O parâmetro 'header_content_type' não possui a chave 'Content-Type' com o tipo do anexo")
|
422
429
|
|
423
430
|
nome_arquivo = os.path.basename(anexo_path)
|
424
|
-
|
425
|
-
with open(anexo_path, 'rb') as f:
|
426
|
-
|
427
|
-
file_data = f
|
428
|
-
|
429
431
|
try:
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
432
|
+
with open(anexo_path, 'rb') as f:
|
433
|
+
url = f"{self.api_url}/now/attachment/file?table_name={tabela}&table_sys_id={sys_id}&file_name={nome_arquivo}"
|
434
|
+
response = requests.post(url, headers=header_content_type, auth=(self.__username, self.__password), data=f, timeout=timeout)
|
435
|
+
|
436
|
+
logging.debug("Arquivo adicionado no ticket")
|
437
|
+
return {"success": True, "result" : response}
|
435
438
|
|
436
439
|
except Exception as e:
|
437
440
|
return {"success" : False, "result" : None, "error" : str(e)}
|
438
441
|
|
439
442
|
|
440
|
-
def
|
443
|
+
def __valida_header_content_type(self, anexo_path, header_content_type):
|
441
444
|
"""
|
442
445
|
Valida e define o cabeçalho `Content-Type` baseado na extensão do arquivo anexado.
|
443
446
|
|
@@ -477,17 +480,106 @@ class ServiceNow:
|
|
477
480
|
|
478
481
|
header_content_type = {"Content-Type": "text/plain"}
|
479
482
|
|
480
|
-
#
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
# # Validação de 'header_content_type'
|
485
|
-
# if not isinstance(header_content_type, dict):
|
486
|
-
# raise ValueError("O parâmetro 'header_content_type' precisa ser um dicionário contendo o 'Content-Type' do arquivo a ser anexado. (Ex: {\"Content-Type\": \"application/zip\"})")
|
483
|
+
# Validação de 'header_content_type'
|
484
|
+
if not isinstance(header_content_type, dict):
|
485
|
+
raise ValueError("O parâmetro 'header_content_type' precisa ser um dicionário contendo o 'Content-Type' do arquivo a ser anexado. (Ex: {\"Content-Type\": \"application/zip\"})")
|
487
486
|
|
487
|
+
|
488
488
|
return header_content_type
|
489
489
|
|
490
490
|
|
491
|
+
def download_anexo(self, sys_id_file : str, file_path : str, timeout : int = 15):
|
492
|
+
"""
|
493
|
+
Faz o download de um anexo do ServiceNow utilizando o `sys_id` do arquivo e salva no caminho especificado.
|
494
|
+
|
495
|
+
Parâmetros:
|
496
|
+
sys_id_file (str): O identificador único (sys_id) do arquivo no ServiceNow.
|
497
|
+
file_path (str): O caminho completo onde o arquivo será salvo localmente.
|
498
|
+
timeout (int, opcional): O tempo limite, em segundos, para a requisição HTTP. Padrão é 15 segundos.
|
499
|
+
|
500
|
+
Retorna:
|
501
|
+
bool: Retorna `True` se o arquivo foi salvo com sucesso no caminho especificado.
|
502
|
+
dict: Em caso de erro, retorna um dicionário com os seguintes campos:
|
503
|
+
- "success" (bool): Indica se a operação foi bem-sucedida (`False` em caso de falha).
|
504
|
+
- "error" (str): Mensagem de erro detalhada em caso de falha.
|
505
|
+
- "path" (str, opcional): O caminho do arquivo salvo, caso tenha sido criado após a criação de diretórios.
|
506
|
+
|
507
|
+
Comportamento:
|
508
|
+
- Em caso de sucesso na requisição HTTP (status code 200), o arquivo é salvo no `file_path`.
|
509
|
+
- Caso o caminho do arquivo não exista, tenta criá-lo automaticamente.
|
510
|
+
- Registra logs de erros ou informações em caso de falha.
|
511
|
+
|
512
|
+
Exceções Tratadas:
|
513
|
+
- FileNotFoundError: Se o caminho especificado não existir, tenta criar os diretórios necessários.
|
514
|
+
- Exception: Registra quaisquer outros erros inesperados durante o salvamento.
|
515
|
+
|
516
|
+
Logs:
|
517
|
+
- `logging.debug`: Para erros de salvamento no arquivo.
|
518
|
+
- `logging.error`: Para erros genéricos durante o processo.
|
519
|
+
- `logging.info`: Para informações sobre falhas na requisição HTTP.
|
520
|
+
|
521
|
+
Exemplo:
|
522
|
+
obj.download_anexo("abc123sysid", "/caminho/para/salvar/arquivo.txt")
|
523
|
+
{'success': False, 'error': 'Status code: 404'}
|
524
|
+
"""
|
525
|
+
try:
|
526
|
+
DownloadFileValidator(sys_id_file=sys_id_file, file_path=file_path)
|
527
|
+
except ValidationError as e:
|
528
|
+
raise ValueError("Erro na validação dos dados de input do método:", e.errors())
|
529
|
+
|
530
|
+
url = f"{self.api_url}/now/attachment/{sys_id_file}/file"
|
531
|
+
response = self.__request_download(url=url, timeout=timeout)
|
532
|
+
response = response.get("result")
|
533
|
+
if response.status_code == 200:
|
534
|
+
try:
|
535
|
+
if not os.path.exists(file_path):
|
536
|
+
diretorio = os.path.dirname(file_path)
|
537
|
+
print(diretorio)
|
538
|
+
os.makedirs(diretorio, exist_ok=True)
|
539
|
+
logging.debug(f"Diretorio criado: {diretorio}")
|
540
|
+
with open(file_path, 'wb') as f:
|
541
|
+
f.write(response.content)
|
542
|
+
return {"success" : True, "path" : file_path }
|
543
|
+
|
544
|
+
except FileNotFoundError:
|
545
|
+
try:
|
546
|
+
path = os.path.dirname(file_path)
|
547
|
+
os.makedirs(path)
|
548
|
+
with open(file_path, 'wb') as f:
|
549
|
+
f.write(response.content)
|
550
|
+
return {"success" : True, "path" : file_path }
|
551
|
+
except Exception as e:
|
552
|
+
logging.debug(f"Erro ao salvar o arquivo. Erro: {e}")
|
553
|
+
return {"success" : False, "error" : str(e) }
|
554
|
+
except Exception as e:
|
555
|
+
logging.error(f"Erro ao salvar o arquivo. Erro: {e}")
|
556
|
+
return {"success" : False, "error" : str(e) }
|
557
|
+
else:
|
558
|
+
logging.debug(f"{response.status_code}")
|
559
|
+
return {"success" : False, "error" : f"Status code: {response.status_code }"}
|
560
|
+
|
561
|
+
def get_variables_from_ticket(self, sys_id : str, campos : str = ''):
|
562
|
+
"""
|
563
|
+
Obtém as variáveis associadas ao ticket.
|
564
|
+
args:
|
565
|
+
sys_id : STR - Id do ticket
|
566
|
+
"""
|
567
|
+
if isinstance(campos, list):
|
568
|
+
campos = ','.join(campos)
|
569
|
+
if campos == "":
|
570
|
+
campos = 'name,question_text,type,default_value, sys_id'
|
571
|
+
|
572
|
+
logging.debug(f"Obtendo variáveis do ticket {sys_id}")
|
573
|
+
url = f"{self.api_url}/now/table/item_option_new"
|
574
|
+
params = {
|
575
|
+
'sysparm_query': f'cat_item={sys_id}',
|
576
|
+
'sysparm_display_value': 'true',
|
577
|
+
'sysparm_fields': campos,
|
578
|
+
}
|
579
|
+
response = self.request(url, params=params)
|
580
|
+
return response
|
581
|
+
|
582
|
+
|
491
583
|
def get_anexo(self, sys_id: str = None, tabela: str = None, campo: str = 'default', download_dir:str=None, timeout:int=15)->dict:
|
492
584
|
"""Traz os anexos de um campo do ticket especificado
|
493
585
|
|
@@ -508,19 +600,6 @@ class ServiceNow:
|
|
508
600
|
except ValidationError as e:
|
509
601
|
raise ValueError("Erro na validação dos dados de input do método:", e.errors())
|
510
602
|
|
511
|
-
# # Validação de 'sys_id'
|
512
|
-
# if not isinstance(sys_id, str) or not sys_id.strip():
|
513
|
-
# raise ValueError("O parâmetro 'sys_id' precisa ser uma string não vazia com o sys_id do ticket.")
|
514
|
-
|
515
|
-
# # Validação de 'tabela'
|
516
|
-
# if not isinstance(tabela, str) or not tabela.strip():
|
517
|
-
# raise ValueError("O parâmetro 'tabela' precisa ser uma string não vazia com o nome da tabela do ticket.")
|
518
|
-
|
519
|
-
# # Validação de 'timeout'
|
520
|
-
# if not isinstance(timeout, int):
|
521
|
-
# raise ValueError("O parâmetro 'timeout' precisa ser um valor (int) em segundos.")
|
522
|
-
|
523
|
-
# Validação de 'download_dir'
|
524
603
|
if download_dir is not None:
|
525
604
|
if not isinstance(download_dir, str) or not download_dir.strip():
|
526
605
|
raise ValueError("O parâmetro 'download_dir' precisa ser a pasta pra onde o anexo será feito o download.")
|
@@ -535,12 +614,7 @@ class ServiceNow:
|
|
535
614
|
|
536
615
|
# Convert bytes to base64
|
537
616
|
def __bytes_to_base64(image_bytes):
|
538
|
-
# base64_encoded = base64.b64encode(image_bytes)
|
539
|
-
|
540
|
-
# # Decode the bytes to a string (UTF-8 encoding)
|
541
|
-
# base64_string = base64_encoded.decode('utf-8')
|
542
617
|
|
543
|
-
# # return base64_string
|
544
618
|
return base64.b64encode(image_bytes).decode('utf-8')
|
545
619
|
|
546
620
|
def __formatar_tamanho(tamanho_bytes):
|
@@ -564,8 +638,8 @@ class ServiceNow:
|
|
564
638
|
try:
|
565
639
|
if campo == 'default':
|
566
640
|
url = f"{self.api_url}/now/attachment?sysparm_query=table_name={tabela}^table_sys_id={sys_id}"
|
567
|
-
response = self.
|
568
|
-
|
641
|
+
response = self.__request_download(url, timeout=timeout)
|
642
|
+
response = response.get("result")
|
569
643
|
if response.status_code == 200:
|
570
644
|
for attachment in response.json().get("result", []):
|
571
645
|
arquivo = {
|
@@ -574,7 +648,8 @@ class ServiceNow:
|
|
574
648
|
"content_type": attachment["content_type"],
|
575
649
|
"base64": None
|
576
650
|
}
|
577
|
-
byte_response = self.
|
651
|
+
byte_response = self.__request_download(attachment["download_link"], timeout=timeout)
|
652
|
+
byte_response = byte_response.get("result")
|
578
653
|
if byte_response.status_code == 200:
|
579
654
|
arquivo["base64"] = __bytes_to_base64(byte_response.content)
|
580
655
|
if download_dir:
|
@@ -586,13 +661,15 @@ class ServiceNow:
|
|
586
661
|
|
587
662
|
else:
|
588
663
|
url = f"{self.api_url}/now/table/{tabela}?sysparm_query=sys_id={sys_id}&sysparm_fields={campo}&sysparm_display_value=all"
|
589
|
-
response = self.
|
664
|
+
response = self.__request_download(url, timeout=timeout)
|
665
|
+
response = response.get("result")
|
590
666
|
if response.status_code == 200 and response.json().get("result"):
|
591
667
|
campo_data = response.json()["result"][0].get(campo)
|
592
668
|
if campo_data:
|
593
669
|
attachment_id = campo_data["value"]
|
594
670
|
attachment_url = f"{self.api_url}/now/attachment/{attachment_id}/file"
|
595
|
-
byte_response = self.
|
671
|
+
byte_response = self.__request_download(attachment["download_link"], timeout=timeout)
|
672
|
+
byte_response = byte_response.get("result")
|
596
673
|
if byte_response.status_code == 200:
|
597
674
|
arquivo = {
|
598
675
|
"file_name": campo_data["display_value"],
|
@@ -609,115 +686,4 @@ class ServiceNow:
|
|
609
686
|
|
610
687
|
except Exception as e:
|
611
688
|
logging.debug("Erro ao obter anexos.")
|
612
|
-
return {"success": False, "error": str(e)}
|
613
|
-
|
614
|
-
# # Fazendo download do anexo do campo padrao do ticket
|
615
|
-
# if campo == 'default':
|
616
|
-
|
617
|
-
# logging.debug(f"verificando o campo '{campo}' de anexo")
|
618
|
-
|
619
|
-
# try:
|
620
|
-
# #url = f"{SERVICENOW_API_URL}/now/attachment?sysparm_query=table_name=sc_req_item^table_sys_id={sys_id}"
|
621
|
-
# url = f"{self.api_url}/now/attachment?sysparm_query=table_name={tabela}^table_sys_id={sys_id}"
|
622
|
-
# response = self.request(url)
|
623
|
-
# # response = requests.get(url, auth=(self.username, self.password), verify=True, timeout=timeout)
|
624
|
-
# if response.status_code == 200 and len(response.json()["result"]) >= 1:
|
625
|
-
|
626
|
-
# for attachment in response.json()["result"]:
|
627
|
-
|
628
|
-
# # print("attachment")
|
629
|
-
# # print(attachment)
|
630
|
-
# arquivo = {}
|
631
|
-
# arquivo["file_name"] = attachment["file_name"]
|
632
|
-
# arquivo["size"] = __formatar_tamanho(attachment["size_bytes"]["display_value"])
|
633
|
-
# arquivo["content_type"] = attachment["content_type"]
|
634
|
-
# #arquivo["table_sys_id"] = attachment["table_sys_id"]
|
635
|
-
|
636
|
-
# try:
|
637
|
-
# byte_response = self.request(attachment["download_link"])
|
638
|
-
# # byte_response = requests.get(attachment["download_link"], auth=(self.username, self.password), verify=True, timeout=timeout)
|
639
|
-
|
640
|
-
# if byte_response.status_code == 200:
|
641
|
-
|
642
|
-
# arquivo["base64"] = __bytes_to_base64(byte_response.content)
|
643
|
-
|
644
|
-
# if download_dir is not None:
|
645
|
-
# with open(arquivo["file_name"],'wb') as download_file:
|
646
|
-
# download_file.write(byte_response.content)
|
647
|
-
|
648
|
-
# #del arquivo["sys_id"]
|
649
|
-
# #del arquivo["download_link"]
|
650
|
-
# #del arquivo["table_sys_id"]
|
651
|
-
# anexo_dict["anexos"].append(arquivo)
|
652
|
-
# #return JSONResponse(content=arquivo, status_code=byte_response.status_code, media_type="application/json")
|
653
|
-
# # Requisicao não OK (!= 200)
|
654
|
-
# return {"success" : True, "result" : anexo_dict, "error": None, "status_code" : byte_response.status_code }
|
655
|
-
|
656
|
-
# except Exception as e:
|
657
|
-
# return {"success" : False, "result" : None, "error" : e, "status_code" : byte_response.status_code}
|
658
|
-
|
659
|
-
# elif response.status_code != 200:
|
660
|
-
# return {"success" : False , "result" : response.json(), "status_code" : response.status_code, "error" : None}
|
661
|
-
|
662
|
-
# except Exception as e:
|
663
|
-
# return {"success" : False, "result" : None, "error" : e}
|
664
|
-
|
665
|
-
# # Fazendo download do anexo do campo especificado do ticket
|
666
|
-
# else:
|
667
|
-
|
668
|
-
# logging.debug(f"verificando o campo '{campo}' de anexo")
|
669
|
-
|
670
|
-
# url = f"{self.api_url}/now/table/{tabela}?sysparm_query=sys_id={sys_id}&sysparm_fields={campo}&sysparm_display_value=all&sysparam_limit=1"
|
671
|
-
# try:
|
672
|
-
# response = self.request(url)
|
673
|
-
# # response = requests.get(url, auth=(self.username, self.password), verify=True)
|
674
|
-
|
675
|
-
# # Requisicao OK e com anexo
|
676
|
-
# if response.status_code == 200 and len(response.json()["result"]) >= 1:
|
677
|
-
|
678
|
-
# for ticket_data in response.json()["result"]:
|
679
|
-
|
680
|
-
# if len(ticket_data) >= 1:
|
681
|
-
|
682
|
-
# try:
|
683
|
-
|
684
|
-
# #temp_file_name = ticket_data[campo]["display_value"]
|
685
|
-
# temp_sys_id = ticket_data[campo]["value"]
|
686
|
-
# url = f"{self.api_url}/now/table/sys_attachment?sysparm_query=sys_id={temp_sys_id}&sysparm_display_value=all&sysparam_limit=1"
|
687
|
-
# response = self.request(url=url)
|
688
|
-
|
689
|
-
# except Exception as e:
|
690
|
-
# return {"success" : False, "error" : e, "result" : None}
|
691
|
-
|
692
|
-
# if response.status_code == 200:
|
693
|
-
|
694
|
-
# attachment = response.json()["result"][0]
|
695
|
-
# arquivo = {}
|
696
|
-
# arquivo["file_name"] = attachment["file_name"]["display_value"]
|
697
|
-
# arquivo["size"] = __formatar_tamanho(attachment["size_bytes"]["display_value"])
|
698
|
-
# #arquivo["sys_id"] = attachment["sys_id"]
|
699
|
-
# arquivo["content_type"] = attachment["content_type"]["value"]
|
700
|
-
# #attach_sys_id = attachment["sys_id"]["display_value"]
|
701
|
-
# #attach_sys_id_table = attachment["table_sys_id"]["value"]
|
702
|
-
# #url = f"{self.api_url}/now/attachment/{sys_id}/file"
|
703
|
-
# try:
|
704
|
-
|
705
|
-
# url = f"{self.api_url}/now/attachment/{temp_sys_id}/file"
|
706
|
-
# byte_response = self.request(url)
|
707
|
-
# # byte_response = requests.get(url, auth=(self.username, self.password), verify=True)
|
708
|
-
# arquivo["base64"] = __bytes_to_base64(byte_response.content)
|
709
|
-
# anexo_dict["anexos"].append(arquivo)
|
710
|
-
# if download_dir is not None:
|
711
|
-
|
712
|
-
# with open(arquivo["file_name"],'wb') as download_file:
|
713
|
-
# download_file.write(byte_response.content)
|
714
|
-
# return {"success" : True, "status_code" : response.status_code, "error" : None, "result" : anexo_dict}
|
715
|
-
# except Exception as e:
|
716
|
-
# return {"success" : False, "status_code" : response.status_code, "error" : e, "result" : response.json()}
|
717
|
-
|
718
|
-
# # Requisicao não OK (!= 200)
|
719
|
-
# elif response.status_code != 200:
|
720
|
-
# return {"success" : False, "status_code" : response.status_code, "error" : e, "result" : response.json()}
|
721
|
-
|
722
|
-
# except Exception as e:
|
723
|
-
# return {"success" : False, "error" : e, "result" : None}
|
689
|
+
return {"success": False, "error": str(e)}
|