csc-cia-stne 0.0.13__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 +8 -0
- csc_cia_stne/bc_correios.py +516 -0
- csc_cia_stne/bc_sta.py +301 -0
- csc_cia_stne/cia_logging.py +149 -0
- csc_cia_stne/gcp_bigquery.py +182 -0
- csc_cia_stne/karavela.py +123 -0
- csc_cia_stne/logger.py +155 -0
- csc_cia_stne/servicenow.py +529 -0
- csc_cia_stne/stne_admin.py +423 -0
- csc_cia_stne/utilitarios.py +72 -0
- csc_cia_stne-0.0.13.dist-info/LICENCE +21 -0
- csc_cia_stne-0.0.13.dist-info/METADATA +25 -0
- csc_cia_stne-0.0.13.dist-info/RECORD +15 -0
- csc_cia_stne-0.0.13.dist-info/WHEEL +5 -0
- csc_cia_stne-0.0.13.dist-info/top_level.txt +1 -0
@@ -0,0 +1,529 @@
|
|
1
|
+
import requests
|
2
|
+
import base64, json
|
3
|
+
import os
|
4
|
+
from .logger import logger
|
5
|
+
|
6
|
+
class ServiceNow:
|
7
|
+
|
8
|
+
def __init__(self, username: str = None, password: str = None, env: str = None) -> None:
|
9
|
+
# Verifica se todos os parâmetros foram fornecidos e não estão vazios
|
10
|
+
if not all([username and username.strip(), password and password.strip(), env and env.strip()]):
|
11
|
+
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)")
|
12
|
+
|
13
|
+
# Normaliza o valor de 'env' para maiúsculas
|
14
|
+
env = env.strip().upper()
|
15
|
+
|
16
|
+
# Dicionário de ambientes válidos e URLs correspondentes
|
17
|
+
valid_envs = {
|
18
|
+
'DEV': 'https://stonedev.service-now.com/api',
|
19
|
+
'QA': 'https://stoneqas.service-now.com/api',
|
20
|
+
'QAS': 'https://stoneqas.service-now.com/api',
|
21
|
+
'PROD': 'https://stone.service-now.com/api'
|
22
|
+
}
|
23
|
+
|
24
|
+
# Verifica se 'env' é válido
|
25
|
+
if env not in valid_envs:
|
26
|
+
raise ValueError("O valor de 'env' precisa ser 'dev', 'qa', 'qas' ou 'prod'.")
|
27
|
+
|
28
|
+
# Atribui as variáveis de instância
|
29
|
+
self.username = username.strip()
|
30
|
+
self.password = password.strip()
|
31
|
+
self.env = env
|
32
|
+
self.api_url = valid_envs[env]
|
33
|
+
self.api_header = {"Content-Type":"application/json","Accept":"application/json"}
|
34
|
+
|
35
|
+
# Criação de funções básicas para reutilizar nas funções especificas
|
36
|
+
|
37
|
+
def __auth(self):
|
38
|
+
"""
|
39
|
+
Retorna o e-mail e senha para realizar a autenticação.
|
40
|
+
"""
|
41
|
+
return (self.username, self.password)
|
42
|
+
|
43
|
+
def request (self, url, params = ""):
|
44
|
+
try:
|
45
|
+
response = requests.get(
|
46
|
+
url,
|
47
|
+
params=params,
|
48
|
+
auth=self.__auth(),
|
49
|
+
headers=self.api_header,
|
50
|
+
timeout=15,
|
51
|
+
verify=True
|
52
|
+
)
|
53
|
+
|
54
|
+
# VALIDA SE HOUVE SUCESSO NA REQUISIÇÃO
|
55
|
+
response.raise_for_status()
|
56
|
+
|
57
|
+
# Analisa o conteúdo da resposta JSON
|
58
|
+
result = response.json()
|
59
|
+
if "result" in result:
|
60
|
+
return result["result"]
|
61
|
+
else:
|
62
|
+
logger.warning("A resposta não contém o campo 'result'.")
|
63
|
+
return {}
|
64
|
+
|
65
|
+
except requests.exceptions.HTTPError as http_err:
|
66
|
+
logger.error(f"Erro HTTP ao buscar os detalhes do ticket: {http_err}")
|
67
|
+
raise
|
68
|
+
except requests.exceptions.RequestException as req_err:
|
69
|
+
logger.error(f"Erro ao buscar os detalhes do ticket: {req_err}")
|
70
|
+
raise
|
71
|
+
except Exception as e:
|
72
|
+
logger.error(f"Erro inesperado: {e}")
|
73
|
+
raise
|
74
|
+
|
75
|
+
def put(self, url, payload):
|
76
|
+
|
77
|
+
payload = json.dumps(payload)
|
78
|
+
|
79
|
+
try:
|
80
|
+
response = requests.put(
|
81
|
+
f"{url}",
|
82
|
+
auth=self.__auth(),
|
83
|
+
headers=self.api_header,
|
84
|
+
data=f"{payload}",
|
85
|
+
timeout=15,
|
86
|
+
verify=True
|
87
|
+
)
|
88
|
+
|
89
|
+
# VALIDA SE HOUVE SUCESSO NA REQUISIÇÃO
|
90
|
+
response.raise_for_status()
|
91
|
+
|
92
|
+
# POSSUINDO 'RESULT', TEREMOS O RETORNO DO TICKET ABERTO.
|
93
|
+
result = response.json()
|
94
|
+
if "result" in result:
|
95
|
+
update = result["result"]
|
96
|
+
logger.info(f"Atualização concluída com sucesso. Registro atualizado: {update["sys_id"]} | Alterações: {payload}")
|
97
|
+
else:
|
98
|
+
logger.warning(f"A Resposta da sua requisição não contém o campo 'Result'. Segue o retorno: \n {result} | Alterações: {payload}")
|
99
|
+
|
100
|
+
#TRATAMENTOS DE ERRO
|
101
|
+
except requests.exceptions.HTTPError as http_err:
|
102
|
+
|
103
|
+
logger.error(f"Erro HTTP ao tentar atualizar o ticket: {http_err} \n Reposta da solicitação: {response.json().get("error").get("message")}")
|
104
|
+
raise
|
105
|
+
except requests.exceptions.RequestException as req_err:
|
106
|
+
|
107
|
+
logger.error(f"Erro ao tentar atualizar o ticket: \n {req_err}")
|
108
|
+
raise
|
109
|
+
except Exception as e:
|
110
|
+
logger.error(f"Erro inesperado: \n {e}")
|
111
|
+
raise
|
112
|
+
|
113
|
+
def post(self, url, variables, header_content_type = ""):
|
114
|
+
"""
|
115
|
+
Função para criar um novo ticket no servicenow usando o API REST.
|
116
|
+
|
117
|
+
Parametros:
|
118
|
+
- Payload (Dict): Dicionário contendo os dados que serão utilizados para criar o ticket
|
119
|
+
Retorno:
|
120
|
+
- Dict: Um dicionário contendo os detalhes do ticket criado
|
121
|
+
Raises:
|
122
|
+
- Exception: Se ocorrer um erro ao criar o ticket.
|
123
|
+
|
124
|
+
"""
|
125
|
+
if header_content_type:
|
126
|
+
header = header_content_type
|
127
|
+
else:
|
128
|
+
header = self.api_header
|
129
|
+
|
130
|
+
# Ajustar o Payload para a abertura do ticket
|
131
|
+
payload = {
|
132
|
+
"sysparm_quantity" : "1",
|
133
|
+
"variables" : json.dumps(variables)
|
134
|
+
}
|
135
|
+
try:
|
136
|
+
response = requests.post(
|
137
|
+
f"{url}",
|
138
|
+
auth=self.__auth(),
|
139
|
+
headers=header,
|
140
|
+
data=f"{payload}"
|
141
|
+
)
|
142
|
+
|
143
|
+
# VALIDA SE HOUVE SUCESSO NA REQUISIÇÃO
|
144
|
+
response.raise_for_status()
|
145
|
+
|
146
|
+
# POSSUINDO 'RESULT', TEREMOS O RETORNO DO TICKET ABERTO.
|
147
|
+
result = response.json()
|
148
|
+
if "result" in result:
|
149
|
+
ticket_number = result["result"].get("number")
|
150
|
+
ticket_sys_id = result["result"].get("sys_id")
|
151
|
+
logger.info(f"Ticket registrado com sucesso. Número: {ticket_number} | SYS_ID: {ticket_sys_id}")
|
152
|
+
return result["result"]
|
153
|
+
else:
|
154
|
+
logger.warning(f"A Resposta da sua requisição não contém o campo 'Result'. Segue o retorno: \n {result}")
|
155
|
+
|
156
|
+
#TRATAMENTOS DE ERRO
|
157
|
+
except requests.exceptions.HTTPError as http_err:
|
158
|
+
|
159
|
+
logger.error(f"Erro HTTP ao tentar registrar o ticket: {http_err} \n Reposta da solicitação: {response.json().get("error").get("message")}")
|
160
|
+
raise
|
161
|
+
except requests.exceptions.RequestException as req_err:
|
162
|
+
|
163
|
+
logger.error(f"Erro ao tentar registrar o ticket: \n {req_err}")
|
164
|
+
raise
|
165
|
+
except Exception as e:
|
166
|
+
logger.error(f"Erro inesperado: \n {e}")
|
167
|
+
raise
|
168
|
+
|
169
|
+
def listar_tickets(self, tabela: str = None, campos: list = None, query: str = None, limite: int = 50, timeout:int=15)->dict:
|
170
|
+
"""lista tickets do ServiceNow
|
171
|
+
|
172
|
+
Args:
|
173
|
+
tabela (str): tabela do ServiceNow de onde a query será feita
|
174
|
+
campos (list): lista de campos com valores a trazer
|
175
|
+
query (str): query do ServiceNow
|
176
|
+
limite (int, optional): quantidade máxima de tickets para trazer. Default=50
|
177
|
+
timeout (int, optional): segundos para a requisicao dar timeout. Default=15
|
178
|
+
|
179
|
+
Returns:
|
180
|
+
dict: dicionário com o resultado da query
|
181
|
+
"""
|
182
|
+
# Validação de 'tabela'
|
183
|
+
if not tabela or not tabela.strip():
|
184
|
+
raise ValueError("O parâmetro 'tabela' precisa ser especificado com o nome da tabela de onde os tickets serão listados.")
|
185
|
+
|
186
|
+
# Validação de 'campos'
|
187
|
+
if not isinstance(campos, list) or not campos or not all(isinstance(campo, str) and campo.strip() for campo in campos):
|
188
|
+
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.")
|
189
|
+
|
190
|
+
# Validação de 'query'
|
191
|
+
if not query or not query.strip():
|
192
|
+
raise ValueError("O parâmetro 'query' precisa ser uma string não vazia.")
|
193
|
+
|
194
|
+
# Validação de 'timeout'
|
195
|
+
if not isinstance(timeout, int):
|
196
|
+
raise ValueError("O parâmetro 'timeout' precisa ser um valor (int) em segundos.")
|
197
|
+
|
198
|
+
# Validação de 'limite'
|
199
|
+
if not isinstance(limite, int):
|
200
|
+
raise ValueError("O parâmetro 'limite' precisa ser um número inteiro.")
|
201
|
+
|
202
|
+
params = {}
|
203
|
+
params["sysparm_query"] = query
|
204
|
+
params["sysparm_fields"] = ','.join(campos)
|
205
|
+
params["sysparm_display_value"] = "all"
|
206
|
+
params["sysparm_limit"] = limite
|
207
|
+
|
208
|
+
url = f"{self.api_url}/now/table/{tabela}"
|
209
|
+
|
210
|
+
try:
|
211
|
+
response = self.request(url, params)
|
212
|
+
# response = requests.get(url, params=params, auth=(self.username, self.password), headers=self.api_header, verify=True, timeout=timeout)
|
213
|
+
return {"result":True, "content": response.json()}
|
214
|
+
|
215
|
+
except Exception as e:
|
216
|
+
return {}
|
217
|
+
|
218
|
+
def update_ticket(self, tabela: str = None, sys_id: str = None, campos: dict = None, timeout:int=15)->dict:
|
219
|
+
"""Atualiza as informações de um ticket
|
220
|
+
|
221
|
+
Args:
|
222
|
+
tabela (str): Tabela do ServiceNow de onde o ticket pertence
|
223
|
+
sys_id (str): sys_id do ticket a ser atualizado
|
224
|
+
campos (dict): Dicionário com os dados a serem atualizados no ticket
|
225
|
+
timeout (int, optional): segundos para a requisicao dar timeout. Default=15
|
226
|
+
|
227
|
+
Returns:
|
228
|
+
dict: resposta do ServiceNow
|
229
|
+
"""
|
230
|
+
|
231
|
+
# Validação de 'tabela'
|
232
|
+
if not tabela or not tabela.strip():
|
233
|
+
raise ValueError("O parâmetro 'tabela' precisa ser especificado com o nome da tabela de onde o ticket será atualizado.")
|
234
|
+
|
235
|
+
# Validação de 'sys_id'
|
236
|
+
if not sys_id or not sys_id.strip():
|
237
|
+
raise ValueError("O parâmetro 'sys_id' precisa ser especificado com o sys_id do ticket.")
|
238
|
+
|
239
|
+
# Validação de 'campos'
|
240
|
+
if not isinstance(campos, dict):
|
241
|
+
raise ValueError("O parâmetro 'campos' precisa ser um dicionário contendo os campos do ticket a serem atualizados.")
|
242
|
+
|
243
|
+
if "assigned_to" not in campos:
|
244
|
+
|
245
|
+
campos["assigned_to"] = self.username
|
246
|
+
|
247
|
+
try:
|
248
|
+
|
249
|
+
url = f"{self.api_url}/now/table/{tabela}/{sys_id}"
|
250
|
+
response = self.put(url, payload=campos)
|
251
|
+
# response = requests.patch(url, auth=(self.username, self.password), headers=self.api_header, data=str(campos).encode('utf-8'), verify=True, timeout=timeout)
|
252
|
+
|
253
|
+
return response.json()
|
254
|
+
|
255
|
+
except Exception as e:
|
256
|
+
|
257
|
+
raise e
|
258
|
+
|
259
|
+
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):
|
260
|
+
"""Anexa arquivo em um ticket do ServiceNow
|
261
|
+
|
262
|
+
Args:
|
263
|
+
header_content_type (dict): Dicionário contendo a chave 'Content-Type' com a especificação do tipo do arquivo
|
264
|
+
anexo_path (str): Path do arquivo a ser anexado
|
265
|
+
tabela (str): Tabela do ServiceNow de onde o ticket pertence
|
266
|
+
sys_id (str): sys_id do ticket o qual o arquivo será anexado
|
267
|
+
timeout (int, optional): segundos para a requisicao dar timeout. Default=15
|
268
|
+
|
269
|
+
Returns:
|
270
|
+
dict: resposta do ServiceNow
|
271
|
+
"""
|
272
|
+
|
273
|
+
# Validação de 'tabela'
|
274
|
+
if not tabela or not tabela.strip():
|
275
|
+
raise ValueError("O parâmetro 'tabela' precisa ser especificado com o nome da tabela do ticket pra onde o arquivo será anexado.")
|
276
|
+
|
277
|
+
# Validação de 'sys_id'
|
278
|
+
if not sys_id or not sys_id.strip():
|
279
|
+
raise ValueError("O parâmetro 'sys_id' precisa ser especificado com o sys_id do ticket que o arquivo será anexado.")
|
280
|
+
|
281
|
+
# Validação de 'anexo_path'
|
282
|
+
if not anexo_path or not anexo_path.strip():
|
283
|
+
raise ValueError("O parâmetro 'anexo_path' precisa ser especificado com o path para o arquivo a ser anexado.")
|
284
|
+
|
285
|
+
if not os.path.exists(anexo_path):
|
286
|
+
raise FileExistsError(f"O arquivo não foi encontrado ({anexo_path})")
|
287
|
+
|
288
|
+
header_content_type = self.valida_header_content_type(anexo_path)
|
289
|
+
|
290
|
+
# Converte as chaves do dicionário para minúsculas
|
291
|
+
header_content_type_lower = {k.lower(): v for k, v in header_content_type.items()}
|
292
|
+
|
293
|
+
|
294
|
+
|
295
|
+
if "content-type" not in header_content_type_lower:
|
296
|
+
|
297
|
+
raise ValueError("O parâmetro 'header_content_type' não possui a chave 'Content-Type' com o tipo do anexo")
|
298
|
+
|
299
|
+
nome_arquivo = os.path.basename(anexo_path)
|
300
|
+
|
301
|
+
with open(anexo_path, 'rb') as f:
|
302
|
+
|
303
|
+
file_data = f
|
304
|
+
|
305
|
+
try:
|
306
|
+
url = f"{self.api_url}/now/attachment/file?table_name={tabela}&table_sys_id={sys_id}&file_name={nome_arquivo}"
|
307
|
+
response = self.post(url, file_data, header_content_type )
|
308
|
+
# response = requests.post(f"{self.api_url}/now/attachment/file?table_name={tabela}&table_sys_id={sys_id}&file_name={nome_arquivo}", headers=header_content_type, auth=(self.username, self.password), data=file_data, timeout=timeout)
|
309
|
+
return response.json()
|
310
|
+
|
311
|
+
except Exception as e:
|
312
|
+
|
313
|
+
raise e
|
314
|
+
|
315
|
+
def valida_header_content_type(self, anexo_path ):
|
316
|
+
|
317
|
+
# Pré validando 'header_content_type'
|
318
|
+
if os.path.splitext(anexo_path)[1].lower() == ".zip" and header_content_type is None:
|
319
|
+
|
320
|
+
header_content_type = {"Content-Type": "application/zip"}
|
321
|
+
|
322
|
+
elif os.path.splitext(anexo_path)[1].lower() == ".xlsx" and header_content_type is None:
|
323
|
+
|
324
|
+
header_content_type = {"Content-Type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}
|
325
|
+
|
326
|
+
elif os.path.splitext(anexo_path)[1].lower() == ".pdf" and header_content_type is None:
|
327
|
+
|
328
|
+
header_content_type = {"Content-Type": "application/pdf"}
|
329
|
+
|
330
|
+
elif os.path.splitext(anexo_path)[1].lower() == ".txt" and header_content_type is None:
|
331
|
+
|
332
|
+
header_content_type = {"Content-Type": "text/plain"}
|
333
|
+
|
334
|
+
# Validação de 'header_content_type'
|
335
|
+
if not isinstance(header_content_type, dict):
|
336
|
+
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\"})")
|
337
|
+
|
338
|
+
# Validação de 'header_content_type'
|
339
|
+
if not isinstance(header_content_type, dict):
|
340
|
+
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\"})")
|
341
|
+
|
342
|
+
return header_content_type
|
343
|
+
|
344
|
+
def get_anexo(self, sys_id: str = None, tabela: str = None, campo: str = 'default', download_dir:str=None, timeout:int=15)->dict:
|
345
|
+
"""Traz os anexos de um campo do ticket especificado
|
346
|
+
|
347
|
+
Args:
|
348
|
+
sys_id (str): sys_id do ticket
|
349
|
+
tabela (str): tabela do ticket
|
350
|
+
campo (str, optional): campo do anexo
|
351
|
+
timeout (int, optional): segundos para a requisicao dar timeout. Default=15
|
352
|
+
|
353
|
+
Returns:
|
354
|
+
dict: dicionário com os anexos do ticket
|
355
|
+
"""
|
356
|
+
|
357
|
+
# Validação de 'sys_id'
|
358
|
+
if not isinstance(sys_id, str) or not sys_id.strip():
|
359
|
+
raise ValueError("O parâmetro 'sys_id' precisa ser uma string não vazia com o sys_id do ticket.")
|
360
|
+
|
361
|
+
# Validação de 'tabela'
|
362
|
+
if not isinstance(tabela, str) or not tabela.strip():
|
363
|
+
raise ValueError("O parâmetro 'tabela' precisa ser uma string não vazia com o nome da tabela do ticket.")
|
364
|
+
|
365
|
+
# Validação de 'timeout'
|
366
|
+
if not isinstance(timeout, int):
|
367
|
+
raise ValueError("O parâmetro 'timeout' precisa ser um valor (int) em segundos.")
|
368
|
+
|
369
|
+
# Validação de 'download_dir'
|
370
|
+
if download_dir is not None:
|
371
|
+
if not isinstance(download_dir, str) or not download_dir.strip():
|
372
|
+
|
373
|
+
raise ValueError("O parâmetro 'download_dir' precisa ser a pasta pra onde o anexo será feito o download.")
|
374
|
+
|
375
|
+
if not os.path.exists(download_dir):
|
376
|
+
|
377
|
+
raise NotADirectoryError(f"A pasta informada '{download_dir}' não existe")
|
378
|
+
|
379
|
+
# Validação de 'campo'
|
380
|
+
if not isinstance(campo, str) or not campo.strip():
|
381
|
+
raise ValueError("O parâmetro 'campo' precisa ser uma string não vazia com o nome do campo do anexo.")
|
382
|
+
|
383
|
+
campo = str(campo).strip().lower()
|
384
|
+
|
385
|
+
# Convert bytes to base64
|
386
|
+
def __bytes_to_base64(image_bytes):
|
387
|
+
base64_encoded = base64.b64encode(image_bytes)
|
388
|
+
|
389
|
+
# Decode the bytes to a string (UTF-8 encoding)
|
390
|
+
base64_string = base64_encoded.decode('utf-8')
|
391
|
+
|
392
|
+
return base64_string
|
393
|
+
|
394
|
+
def __formatar_tamanho(tamanho_bytes):
|
395
|
+
# Converte o valor de string para inteiro
|
396
|
+
tamanho_bytes = int(tamanho_bytes)
|
397
|
+
|
398
|
+
# Define os múltiplos de bytes
|
399
|
+
unidades = ['B', 'KB', 'MB', 'GB', 'TB']
|
400
|
+
|
401
|
+
# Itera sobre as unidades até encontrar a maior possível
|
402
|
+
for unidade in unidades:
|
403
|
+
if tamanho_bytes < 1024:
|
404
|
+
return f"{tamanho_bytes:.2f} {unidade}"
|
405
|
+
tamanho_bytes /= 1024
|
406
|
+
|
407
|
+
# Caso o valor seja maior que o esperado (Exabyte ou superior)
|
408
|
+
return f"{tamanho_bytes:.2f} PB" # Petabyte
|
409
|
+
|
410
|
+
anexo_dict = {"var_servicenow": campo, "anexos":[]}
|
411
|
+
|
412
|
+
# Fazendo download do anexo do campo padrao do ticket
|
413
|
+
if campo == 'default':
|
414
|
+
|
415
|
+
print(f"verificando o campo '{campo}' de anexo")
|
416
|
+
|
417
|
+
try:
|
418
|
+
#url = f"{SERVICENOW_API_URL}/now/attachment?sysparm_query=table_name=sc_req_item^table_sys_id={sys_id}"
|
419
|
+
url = f"{self.api_url}/now/attachment?sysparm_query=table_name={tabela}^table_sys_id={sys_id}"
|
420
|
+
response = self.request(url)
|
421
|
+
# response = requests.get(url, auth=(self.username, self.password), verify=True, timeout=timeout)
|
422
|
+
if response.status_code == 200 and len(response.json()["result"]) >= 1:
|
423
|
+
|
424
|
+
for attachment in response.json()["result"]:
|
425
|
+
|
426
|
+
print("attachment")
|
427
|
+
print(attachment)
|
428
|
+
arquivo = {}
|
429
|
+
arquivo["file_name"] = attachment["file_name"]
|
430
|
+
arquivo["size"] = __formatar_tamanho(attachment["size_bytes"]["display_value"])
|
431
|
+
arquivo["content_type"] = attachment["content_type"]
|
432
|
+
#arquivo["table_sys_id"] = attachment["table_sys_id"]
|
433
|
+
|
434
|
+
try:
|
435
|
+
byte_response = self.request(attachment["download_link"])
|
436
|
+
# byte_response = requests.get(attachment["download_link"], auth=(self.username, self.password), verify=True, timeout=timeout)
|
437
|
+
|
438
|
+
if byte_response.status_code == 200:
|
439
|
+
|
440
|
+
arquivo["base64"] = __bytes_to_base64(byte_response.content)
|
441
|
+
|
442
|
+
if download_dir is not None:
|
443
|
+
with open(arquivo["file_name"],'wb') as download_file:
|
444
|
+
download_file.write(byte_response.content)
|
445
|
+
|
446
|
+
#del arquivo["sys_id"]
|
447
|
+
#del arquivo["download_link"]
|
448
|
+
#del arquivo["table_sys_id"]
|
449
|
+
anexo_dict["anexos"].append(arquivo)
|
450
|
+
#return JSONResponse(content=arquivo, status_code=byte_response.status_code, media_type="application/json")
|
451
|
+
# Requisicao não OK (!= 200)
|
452
|
+
|
453
|
+
except Exception as e:
|
454
|
+
|
455
|
+
raise e
|
456
|
+
|
457
|
+
elif response.status_code != 200:
|
458
|
+
|
459
|
+
return response.json()
|
460
|
+
|
461
|
+
except Exception as e:
|
462
|
+
|
463
|
+
raise e
|
464
|
+
|
465
|
+
# Fazendo download do anexo do campo especificado do ticket
|
466
|
+
else:
|
467
|
+
|
468
|
+
print(f"verificando o campo '{campo}' de anexo")
|
469
|
+
|
470
|
+
url = f"{self.api_url}/now/table/{tabela}?sysparm_query=sys_id={sys_id}&sysparm_fields={campo}&sysparm_display_value=all&sysparam_limit=1"
|
471
|
+
try:
|
472
|
+
response = requests.get(url, auth=(self.username, self.password), verify=True)
|
473
|
+
|
474
|
+
# Requisicao OK e com anexo
|
475
|
+
if response.status_code == 200 and len(response.json()["result"]) >= 1:
|
476
|
+
|
477
|
+
for ticket_data in response.json()["result"]:
|
478
|
+
|
479
|
+
if len(ticket_data) >= 1:
|
480
|
+
|
481
|
+
try:
|
482
|
+
|
483
|
+
#temp_file_name = ticket_data[campo]["display_value"]
|
484
|
+
temp_sys_id = ticket_data[campo]["value"]
|
485
|
+
|
486
|
+
except Exception as e:
|
487
|
+
|
488
|
+
raise e
|
489
|
+
|
490
|
+
url = f"{self.api_url}/now/table/sys_attachment?sysparm_query=sys_id={temp_sys_id}&sysparm_display_value=all&sysparam_limit=1"
|
491
|
+
|
492
|
+
response = requests.get(url, auth=(self.username, self.password), verify=True)
|
493
|
+
|
494
|
+
if response.status_code == 200:
|
495
|
+
|
496
|
+
attachment = response.json()["result"][0]
|
497
|
+
arquivo = {}
|
498
|
+
arquivo["file_name"] = attachment["file_name"]["display_value"]
|
499
|
+
arquivo["size"] = __formatar_tamanho(attachment["size_bytes"]["display_value"])
|
500
|
+
#arquivo["sys_id"] = attachment["sys_id"]
|
501
|
+
arquivo["content_type"] = attachment["content_type"]["value"]
|
502
|
+
#attach_sys_id = attachment["sys_id"]["display_value"]
|
503
|
+
#attach_sys_id_table = attachment["table_sys_id"]["value"]
|
504
|
+
#url = f"{self.api_url}/now/attachment/{sys_id}/file"
|
505
|
+
try:
|
506
|
+
|
507
|
+
url = f"{self.api_url}/now/attachment/{temp_sys_id}/file"
|
508
|
+
byte_response = requests.get(url, auth=(self.username, self.password), verify=True)
|
509
|
+
arquivo["base64"] = __bytes_to_base64(byte_response.content)
|
510
|
+
anexo_dict["anexos"].append(arquivo)
|
511
|
+
if download_dir is not None:
|
512
|
+
|
513
|
+
with open(arquivo["file_name"],'wb') as download_file:
|
514
|
+
download_file.write(byte_response.content)
|
515
|
+
|
516
|
+
except Exception as e:
|
517
|
+
|
518
|
+
raise e
|
519
|
+
|
520
|
+
# Requisicao não OK (!= 200)
|
521
|
+
elif response.status_code != 200:
|
522
|
+
|
523
|
+
return response.json()
|
524
|
+
|
525
|
+
except Exception as e:
|
526
|
+
|
527
|
+
raise e
|
528
|
+
|
529
|
+
return anexo_dict
|