csc-cia-stne 0.1.2__py3-none-any.whl → 0.1.3__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/google_drive.py +32 -16
- csc_cia_stne/servicenow.py +316 -196
- csc_cia_stne/utilitarios/web_screen/web_screen_botcity.py +2 -0
- csc_cia_stne/utilitarios/web_screen/web_screen_selenium.py +12 -1
- csc_cia_stne/web.py +3 -0
- {csc_cia_stne-0.1.2.dist-info → csc_cia_stne-0.1.3.dist-info}/METADATA +1 -1
- {csc_cia_stne-0.1.2.dist-info → csc_cia_stne-0.1.3.dist-info}/RECORD +10 -10
- {csc_cia_stne-0.1.2.dist-info → csc_cia_stne-0.1.3.dist-info}/WHEEL +0 -0
- {csc_cia_stne-0.1.2.dist-info → csc_cia_stne-0.1.3.dist-info}/licenses/LICENCE +0 -0
- {csc_cia_stne-0.1.2.dist-info → csc_cia_stne-0.1.3.dist-info}/top_level.txt +0 -0
csc_cia_stne/google_drive.py
CHANGED
@@ -175,8 +175,7 @@ class GoogleDrive:
|
|
175
175
|
|
176
176
|
return {"success": False, "result": None, "error": str(e)}
|
177
177
|
|
178
|
-
|
179
|
-
def _validate_folder_existence(self, folder:str, id_folder:str):
|
178
|
+
def _validate_folder_existence(self, folder: str, id_folder: str):
|
180
179
|
"""
|
181
180
|
Verifica a existência de uma pasta no Google Drive.
|
182
181
|
Args:
|
@@ -192,24 +191,39 @@ class GoogleDrive:
|
|
192
191
|
|
193
192
|
try:
|
194
193
|
|
195
|
-
response =
|
194
|
+
response = (
|
195
|
+
self.service.files()
|
196
|
+
.list(
|
197
|
+
q=query,
|
198
|
+
spaces="drive",
|
199
|
+
fields="nextPageToken, files(id, name, mimeType)",
|
200
|
+
pageToken=None,
|
201
|
+
includeItemsFromAllDrives=True,
|
202
|
+
supportsAllDrives=True,
|
203
|
+
)
|
204
|
+
.execute()
|
205
|
+
)
|
196
206
|
|
197
|
-
items = response.get(
|
207
|
+
items = response.get("files", [])
|
198
208
|
|
199
209
|
for item in items:
|
200
210
|
|
201
|
-
if
|
211
|
+
if (
|
212
|
+
item["mimeType"] == "application/vnd.google-apps.folder"
|
213
|
+
and item["name"] == folder
|
214
|
+
):
|
202
215
|
|
203
216
|
return item
|
204
|
-
|
217
|
+
|
205
218
|
return None
|
206
|
-
|
207
|
-
except Exception as e:
|
208
219
|
|
209
|
-
|
220
|
+
except Exception as e:
|
210
221
|
|
222
|
+
raise ValueError(f"Erro tentando procurar pela pasta:{e}")
|
211
223
|
|
212
|
-
def create_folder(
|
224
|
+
def create_folder(
|
225
|
+
self, name: str, parent_folder_id: str, validate_existence: bool = False
|
226
|
+
):
|
213
227
|
"""
|
214
228
|
Cria uma pasta no Google Drive dentro de uma pasta existente.
|
215
229
|
|
@@ -221,7 +235,11 @@ class GoogleDrive:
|
|
221
235
|
str: ID da pasta criada.
|
222
236
|
"""
|
223
237
|
try:
|
224
|
-
CreateFolderValidator(
|
238
|
+
CreateFolderValidator(
|
239
|
+
name=name,
|
240
|
+
parent_folder_id=parent_folder_id,
|
241
|
+
validate_existence=validate_existence,
|
242
|
+
)
|
225
243
|
except ValidationError as e:
|
226
244
|
raise ValueError(
|
227
245
|
"Erro na validação dos dados de input da inicialização da instância:",
|
@@ -250,7 +268,7 @@ class GoogleDrive:
|
|
250
268
|
return {"success": True, "result": folder}
|
251
269
|
except Exception as e:
|
252
270
|
return {"success": False, "result": None, "error": str(e)}
|
253
|
-
|
271
|
+
|
254
272
|
return {"success": True, "result": status_existence}
|
255
273
|
|
256
274
|
def list_items_folder(
|
@@ -342,7 +360,7 @@ class GoogleDrive:
|
|
342
360
|
except Exception as e:
|
343
361
|
return {"success": False, "result": None}
|
344
362
|
|
345
|
-
def download_others_files(self, file: str,
|
363
|
+
def download_others_files(self, file: str, path: str):
|
346
364
|
"""
|
347
365
|
Obtém o conteúdo de um arquivo armazenado nos seguintes formatos:
|
348
366
|
.xlsx, .pdf, .jpg, etc.
|
@@ -373,9 +391,7 @@ class GoogleDrive:
|
|
373
391
|
if not os.path.exists(path):
|
374
392
|
os.makedirs(path)
|
375
393
|
try:
|
376
|
-
request = self.service.files().get_media(
|
377
|
-
fileId=file.get("id")
|
378
|
-
)
|
394
|
+
request = self.service.files().get_media(fileId=file.get("id"))
|
379
395
|
file_path = f"{path}{file["name"]}"
|
380
396
|
with open(file_path, "wb") as f:
|
381
397
|
f.write(request.execute())
|
csc_cia_stne/servicenow.py
CHANGED
@@ -2,12 +2,15 @@ import requests
|
|
2
2
|
import base64, json
|
3
3
|
import os
|
4
4
|
import logging
|
5
|
-
from pydantic import
|
5
|
+
from pydantic import ValidationError
|
6
6
|
from .utilitarios.validations.ServiceNowValidator import *
|
7
7
|
|
8
|
+
|
8
9
|
class ServiceNow:
|
9
|
-
|
10
|
-
def __init__(
|
10
|
+
|
11
|
+
def __init__(
|
12
|
+
self, username: str = None, password: str = None, env: str = None
|
13
|
+
) -> None:
|
11
14
|
"""
|
12
15
|
Inicializa uma instância da classe ServiceNow.
|
13
16
|
|
@@ -15,10 +18,10 @@ class ServiceNow:
|
|
15
18
|
username (str): Nome de usuário para autenticação. Obrigatório e não pode ser nulo ou vazio.
|
16
19
|
password (str): Senha para autenticação. Obrigatória e não pode ser nula ou vazia.
|
17
20
|
env (str): Ambiente no qual a instância será utilizada. Deve ser 'dev', 'qa', 'qas' ou 'prod'.
|
18
|
-
|
21
|
+
|
19
22
|
Raises:
|
20
23
|
ValueError: Caso qualquer um dos parâmetros não seja fornecido, seja nulo ou vazio, ou se 'env' não for um valor válido.
|
21
|
-
|
24
|
+
|
22
25
|
Atributos:
|
23
26
|
username (str): Nome de usuário normalizado.
|
24
27
|
password (str): Senha normalizada.
|
@@ -27,47 +30,53 @@ class ServiceNow:
|
|
27
30
|
api_header (dict): Cabeçalhos padrão para requisições API.
|
28
31
|
"""
|
29
32
|
try:
|
30
|
-
InitParamsValidator(username=username, password=password, env=env
|
33
|
+
InitParamsValidator(username=username, password=password, env=env)
|
31
34
|
except ValidationError as e:
|
32
|
-
raise ValueError(
|
33
|
-
|
35
|
+
raise ValueError(
|
36
|
+
"Erro na validação dos dados de input da inicialização da instância 'ServiceNow':",
|
37
|
+
e.errors(),
|
38
|
+
)
|
39
|
+
|
34
40
|
# Normaliza o valor de 'env' para maiúsculas
|
35
41
|
env = env.strip().upper()
|
36
42
|
|
37
43
|
# Dicionário de ambientes válidos e URLs correspondentes
|
38
44
|
valid_envs = {
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
45
|
+
"DEV": "https://stonedev.service-now.com/api",
|
46
|
+
"QA": "https://stoneqas.service-now.com/api",
|
47
|
+
"QAS": "https://stoneqas.service-now.com/api",
|
48
|
+
"PROD": "https://stone.service-now.com/api",
|
43
49
|
}
|
44
50
|
|
45
51
|
# Verifica se 'env' é válido
|
46
52
|
if env not in valid_envs:
|
47
|
-
raise ValueError(
|
53
|
+
raise ValueError(
|
54
|
+
"O valor de 'env' precisa ser 'dev', 'qa', 'qas' ou 'prod'."
|
55
|
+
)
|
48
56
|
|
49
57
|
# Atribui as variáveis de instância
|
50
58
|
self.__username = username.strip()
|
51
59
|
self.__password = password.strip()
|
52
60
|
self.env = env
|
53
61
|
self.api_url = valid_envs[env]
|
54
|
-
self.api_header = {
|
55
|
-
|
62
|
+
self.api_header = {
|
63
|
+
"Content-Type": "application/json",
|
64
|
+
"Accept": "application/json",
|
65
|
+
}
|
56
66
|
|
57
67
|
def __auth(self):
|
58
68
|
"""
|
59
|
-
|
69
|
+
Retorna o e-mail e senha para realizar a autenticação.
|
60
70
|
"""
|
61
71
|
return (self.__username, self.__password)
|
62
|
-
|
63
72
|
|
64
|
-
def request
|
73
|
+
def request(self, url: str, params: str = "", timeout: int = 15):
|
65
74
|
"""
|
66
75
|
Realiza uma requisição GET para a URL especificada.
|
67
76
|
|
68
77
|
Parâmetros:
|
69
78
|
url (str): URL para a qual a requisição será enviada.
|
70
|
-
params (dict, opcional): Parâmetros de consulta (query parameters) a serem incluídos na requisição.
|
79
|
+
params (dict, opcional): Parâmetros de consulta (query parameters) a serem incluídos na requisição.
|
71
80
|
Padrão é uma string vazia.
|
72
81
|
|
73
82
|
Retorno:
|
@@ -93,49 +102,50 @@ class ServiceNow:
|
|
93
102
|
try:
|
94
103
|
RequestValidator(url=url, params=params, timeout=timeout)
|
95
104
|
except ValidationError as e:
|
96
|
-
raise ValueError(
|
97
|
-
|
105
|
+
raise ValueError(
|
106
|
+
"Erro na validação dos dados de input do método:", e.errors()
|
107
|
+
)
|
108
|
+
|
98
109
|
try:
|
99
110
|
response = requests.get(
|
100
|
-
url,
|
111
|
+
url,
|
101
112
|
params=params,
|
102
113
|
auth=self.__auth(),
|
103
114
|
headers=self.api_header,
|
104
115
|
timeout=timeout,
|
105
|
-
verify=True
|
116
|
+
verify=True,
|
106
117
|
)
|
107
118
|
|
108
119
|
# VALIDA SE HOUVE SUCESSO NA REQUISIÇÃO
|
109
120
|
response.raise_for_status()
|
110
121
|
|
111
|
-
|
122
|
+
# Analisa o conteúdo da resposta JSON
|
112
123
|
result = response.json()
|
113
124
|
if "result" in result:
|
114
|
-
return {"success"
|
125
|
+
return {"success": True, "result": result.get("result")}
|
115
126
|
else:
|
116
127
|
logging.debug("A resposta não contém o campo 'result'.")
|
117
|
-
return {"success"
|
128
|
+
return {"success": False, "result": result}
|
118
129
|
|
119
130
|
except requests.exceptions.HTTPError as http_err:
|
120
131
|
logging.debug(f"Erro HTTP ao buscar os detalhes do ticket: {http_err}")
|
121
|
-
return {"success"
|
122
|
-
|
132
|
+
return {"success": False, "result": None, "error": str(http_err)}
|
133
|
+
|
123
134
|
except requests.exceptions.RequestException as req_err:
|
124
135
|
logging.debug(f"Erro ao buscar os detalhes do ticket: {req_err}")
|
125
|
-
return {"success"
|
126
|
-
|
136
|
+
return {"success": False, "result": None, "error": str(req_err)}
|
137
|
+
|
127
138
|
except Exception as e:
|
128
139
|
logging.debug(f"Erro inesperado: {e}")
|
129
|
-
return {"success"
|
130
|
-
|
140
|
+
return {"success": False, "result": None, "error": str(e)}
|
131
141
|
|
132
|
-
def __request_download(self, url, params
|
142
|
+
def __request_download(self, url, params="", timeout=15):
|
133
143
|
"""
|
134
144
|
Realiza uma requisição GET para a URL especificada.
|
135
145
|
|
136
146
|
Parâmetros:
|
137
147
|
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.
|
148
|
+
params (dict, opcional): Parâmetros de consulta (query parameters) a serem incluídos na requisição.
|
139
149
|
Padrão é uma string vazia.
|
140
150
|
|
141
151
|
Retorno:
|
@@ -160,37 +170,36 @@ class ServiceNow:
|
|
160
170
|
"""
|
161
171
|
try:
|
162
172
|
response = requests.get(
|
163
|
-
url,
|
173
|
+
url,
|
164
174
|
params=params,
|
165
175
|
auth=self.__auth(),
|
166
176
|
headers=self.api_header,
|
167
177
|
timeout=timeout,
|
168
|
-
verify=True
|
178
|
+
verify=True,
|
169
179
|
)
|
170
180
|
|
171
181
|
# VALIDA SE HOUVE SUCESSO NA REQUISIÇÃO
|
172
182
|
response.raise_for_status()
|
173
|
-
|
183
|
+
# Analisa o conteúdo da resposta JSON
|
174
184
|
if response.status_code == 200:
|
175
|
-
return
|
185
|
+
return {"success": True, "result": response}
|
176
186
|
else:
|
177
187
|
logging.debug("Erro ao realizar a consulta")
|
178
|
-
return {"success"
|
188
|
+
return {"success": False, "result": response.status_code}
|
179
189
|
|
180
190
|
except requests.exceptions.HTTPError as http_err:
|
181
191
|
logging.debug(f"Erro HTTP ao buscar os detalhes do ticket: {http_err}")
|
182
|
-
return {"success"
|
183
|
-
|
192
|
+
return {"success": False, "error": str(http_err), "result": None}
|
193
|
+
|
184
194
|
except requests.exceptions.RequestException as req_err:
|
185
195
|
logging.debug(f"Erro ao buscar os detalhes do ticket: {req_err}")
|
186
|
-
return {"success"
|
187
|
-
|
196
|
+
return {"success": False, "error": str(req_err), "result": None}
|
197
|
+
|
188
198
|
except Exception as e:
|
189
199
|
logging.debug(f"Erro inesperado: {e}")
|
190
|
-
return {"success"
|
200
|
+
return {"success": False, "error": str(e), "result": None}
|
191
201
|
|
192
|
-
|
193
|
-
def put(self, url, payload, timeout = 15):
|
202
|
+
def put(self, url, payload, timeout=15):
|
194
203
|
"""
|
195
204
|
Realiza uma requisição PUT para a URL especificada.
|
196
205
|
|
@@ -221,18 +230,20 @@ class ServiceNow:
|
|
221
230
|
try:
|
222
231
|
PutValidator(url=url, payload=payload, timeout=timeout)
|
223
232
|
except ValidationError as e:
|
224
|
-
raise ValueError(
|
225
|
-
|
233
|
+
raise ValueError(
|
234
|
+
"Erro na validação dos dados de input do método:", e.errors()
|
235
|
+
)
|
236
|
+
|
226
237
|
payload = json.dumps(payload)
|
227
238
|
|
228
|
-
try:
|
239
|
+
try:
|
229
240
|
response = requests.put(
|
230
241
|
f"{url}",
|
231
242
|
auth=self.__auth(),
|
232
243
|
headers=self.api_header,
|
233
244
|
data=f"{payload}",
|
234
245
|
timeout=timeout,
|
235
|
-
verify=True
|
246
|
+
verify=True,
|
236
247
|
)
|
237
248
|
|
238
249
|
# VALIDA SE HOUVE SUCESSO NA REQUISIÇÃO
|
@@ -242,43 +253,51 @@ class ServiceNow:
|
|
242
253
|
result = response.json()
|
243
254
|
if "result" in result:
|
244
255
|
update = result["result"]
|
245
|
-
logging.debug(
|
246
|
-
|
256
|
+
logging.debug(
|
257
|
+
f"Atualização concluída com sucesso. Registro atualizado: {update['sys_id']} | Alterações: {payload}"
|
258
|
+
)
|
259
|
+
return {"success": True, "result": update}
|
247
260
|
else:
|
248
|
-
logging.debug(
|
249
|
-
|
250
|
-
|
251
|
-
|
261
|
+
logging.debug(
|
262
|
+
f"A Resposta da sua requisição não contém o campo 'Result'. Segue o retorno: \n {result} | Alterações: {payload}"
|
263
|
+
)
|
264
|
+
return {"success": False, "result": result}
|
265
|
+
|
266
|
+
# TRATAMENTOS DE ERRO
|
252
267
|
except requests.exceptions.HTTPError as http_err:
|
253
|
-
logging.debug(
|
254
|
-
|
255
|
-
|
268
|
+
logging.debug(
|
269
|
+
f"Erro HTTP ao tentar atualizar o ticket: {http_err} \n Reposta da solicitação: {response.json().get('error').get('message')}"
|
270
|
+
)
|
271
|
+
return {"success": False, "error": str(http_err), "result": None}
|
272
|
+
|
256
273
|
except requests.exceptions.RequestException as req_err:
|
257
274
|
logging.debug(f"Erro ao tentar atualizar o ticket: \n {req_err}")
|
258
|
-
return {"success"
|
259
|
-
|
275
|
+
return {"success": False, "error": str(req_err), "result": None}
|
276
|
+
|
260
277
|
except Exception as e:
|
261
278
|
logging.debug(f"Erro inesperado: \n {e}")
|
262
|
-
return {"success"
|
279
|
+
return {"success": False, "error": str(e), "result": None}
|
263
280
|
|
264
|
-
|
265
|
-
|
281
|
+
def post(
|
282
|
+
self, url: str, variables: dict, header_content_type="", timeout: int = 15
|
283
|
+
):
|
266
284
|
"""
|
267
|
-
|
285
|
+
Função para criar um novo ticket no servicenow usando o API REST.
|
268
286
|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
287
|
+
Parametros:
|
288
|
+
- Payload (Dict): Dicionário contendo os dados que serão utilizados para criar o ticket
|
289
|
+
Retorno:
|
290
|
+
- Dict: Um dicionário contendo os detalhes do ticket criado
|
291
|
+
Raises:
|
292
|
+
- Exception: Se ocorrer um erro ao criar o ticket.
|
275
293
|
|
276
294
|
"""
|
277
|
-
try:
|
295
|
+
try:
|
278
296
|
PostValidator(url=url, variables=variables)
|
279
297
|
except ValidationError as e:
|
280
|
-
raise ValueError(
|
281
|
-
|
298
|
+
raise ValueError(
|
299
|
+
"Erro na validação dos dados de input do método:", e.errors()
|
300
|
+
)
|
282
301
|
|
283
302
|
if header_content_type:
|
284
303
|
header = header_content_type
|
@@ -286,17 +305,14 @@ class ServiceNow:
|
|
286
305
|
header = self.api_header
|
287
306
|
|
288
307
|
# Ajustar o Payload para a abertura do ticket
|
289
|
-
payload = {
|
290
|
-
|
291
|
-
"variables" : json.dumps(variables)
|
292
|
-
}
|
293
|
-
try:
|
308
|
+
payload = {"sysparm_quantity": "1", "variables": json.dumps(variables)}
|
309
|
+
try:
|
294
310
|
response = requests.post(
|
295
311
|
f"{url}",
|
296
312
|
auth=self.__auth(),
|
297
313
|
headers=header,
|
298
314
|
data=f"{payload}",
|
299
|
-
timeout=timeout
|
315
|
+
timeout=timeout,
|
300
316
|
)
|
301
317
|
|
302
318
|
# VALIDA SE HOUVE SUCESSO NA REQUISIÇÃO
|
@@ -307,28 +323,41 @@ class ServiceNow:
|
|
307
323
|
if "result" in result:
|
308
324
|
ticket_number = result["result"].get("number")
|
309
325
|
ticket_sys_id = result["result"].get("sys_id")
|
310
|
-
logging.debug(
|
311
|
-
|
326
|
+
logging.debug(
|
327
|
+
f"Ticket registrado com sucesso. Número: {ticket_number} | SYS_ID: {ticket_sys_id}"
|
328
|
+
)
|
329
|
+
return {"success": True, "result": result["result"]}
|
312
330
|
else:
|
313
|
-
logging.debug(
|
314
|
-
|
315
|
-
|
316
|
-
|
331
|
+
logging.debug(
|
332
|
+
f"A Resposta da sua requisição não contém o campo 'Result'. Segue o retorno: \n {result}"
|
333
|
+
)
|
334
|
+
return {"success": False, "result": result}
|
335
|
+
|
336
|
+
# TRATAMENTOS DE ERRO
|
317
337
|
except requests.exceptions.HTTPError as http_err:
|
318
338
|
|
319
|
-
logging.debug(
|
320
|
-
|
321
|
-
|
339
|
+
logging.debug(
|
340
|
+
f"Erro HTTP ao tentar registrar o ticket: {http_err} \n Reposta da solicitação: {response.json().get('error').get('message')}"
|
341
|
+
)
|
342
|
+
return {"success": False, "error": str(http_err), "result": None}
|
343
|
+
|
322
344
|
except requests.exceptions.RequestException as req_err:
|
323
345
|
logging.debug(f"Erro ao tentar registrar o ticket: \n {req_err}")
|
324
|
-
return {"success"
|
325
|
-
|
346
|
+
return {"success": False, "error": str(req_err), "result": None}
|
347
|
+
|
326
348
|
except Exception as e:
|
327
349
|
logging.debug(f"Erro inesperado: \n {e}")
|
328
|
-
return {"success"
|
329
|
-
|
330
|
-
|
331
|
-
|
350
|
+
return {"success": False, "error": str(e), "result": None}
|
351
|
+
|
352
|
+
def listar_tickets(
|
353
|
+
self,
|
354
|
+
tabela: str = None,
|
355
|
+
campos: list = None,
|
356
|
+
query: str = None,
|
357
|
+
limite: int = 50,
|
358
|
+
timeout: int = 15,
|
359
|
+
sysparm_display_value: str = "",
|
360
|
+
) -> dict:
|
332
361
|
"""lista tickets do ServiceNow
|
333
362
|
|
334
363
|
Args:
|
@@ -342,30 +371,42 @@ class ServiceNow:
|
|
342
371
|
dict: dicionário com o resultado da query
|
343
372
|
"""
|
344
373
|
try:
|
345
|
-
ListTicketValidator(
|
374
|
+
ListTicketValidator(
|
375
|
+
tabela=tabela,
|
376
|
+
campos=campos,
|
377
|
+
query=query,
|
378
|
+
limite=limite,
|
379
|
+
timeout=timeout,
|
380
|
+
)
|
346
381
|
except ValidationError as e:
|
347
|
-
raise ValueError(
|
348
|
-
|
382
|
+
raise ValueError(
|
383
|
+
"Erro na validação dos dados de input do método:", e.errors()
|
384
|
+
)
|
349
385
|
|
350
386
|
params = {
|
351
|
-
"sysparm_query"
|
352
|
-
"sysparm_fields"
|
353
|
-
"sysparm_display_value"
|
354
|
-
"sysparm_limit"
|
387
|
+
"sysparm_query": query,
|
388
|
+
"sysparm_fields": ",".join(campos),
|
389
|
+
"sysparm_display_value": sysparm_display_value,
|
390
|
+
"sysparm_limit": limite,
|
355
391
|
}
|
356
392
|
|
357
393
|
url = f"{self.api_url}/now/table/{tabela}"
|
358
|
-
|
394
|
+
|
359
395
|
try:
|
360
396
|
response = self.request(url=url, params=params, timeout=timeout)
|
361
397
|
return response
|
362
|
-
|
398
|
+
|
363
399
|
except Exception as e:
|
364
400
|
logging.debug(f"erro: {e}")
|
365
401
|
return str(e)
|
366
402
|
|
367
|
-
|
368
|
-
|
403
|
+
def update_ticket(
|
404
|
+
self,
|
405
|
+
tabela: str = None,
|
406
|
+
sys_id: str = None,
|
407
|
+
payload: dict = None,
|
408
|
+
timeout: int = 15,
|
409
|
+
) -> dict:
|
369
410
|
"""Atualiza as informações de um ticket
|
370
411
|
|
371
412
|
Args:
|
@@ -378,10 +419,14 @@ class ServiceNow:
|
|
378
419
|
dict: resposta do ServiceNow
|
379
420
|
"""
|
380
421
|
try:
|
381
|
-
UpdateTicketValidator(
|
422
|
+
UpdateTicketValidator(
|
423
|
+
tabela=tabela, sys_id=sys_id, payload=payload, timeout=timeout
|
424
|
+
)
|
382
425
|
except ValidationError as e:
|
383
|
-
raise ValueError(
|
384
|
-
|
426
|
+
raise ValueError(
|
427
|
+
"Erro na validação dos dados de input do método:", e.errors()
|
428
|
+
)
|
429
|
+
|
385
430
|
payload["assigned_to"] = self.__username
|
386
431
|
|
387
432
|
try:
|
@@ -393,8 +438,14 @@ class ServiceNow:
|
|
393
438
|
except Exception as e:
|
394
439
|
return str(e)
|
395
440
|
|
396
|
-
|
397
|
-
|
441
|
+
def anexar_arquivo_no_ticket(
|
442
|
+
self,
|
443
|
+
header_content_type: dict = None,
|
444
|
+
anexo_path: str = None,
|
445
|
+
tabela: str = None,
|
446
|
+
sys_id: str = None,
|
447
|
+
timeout: int = 15,
|
448
|
+
):
|
398
449
|
"""Anexa arquivo em um ticket do ServiceNow
|
399
450
|
|
400
451
|
Args:
|
@@ -408,37 +459,53 @@ class ServiceNow:
|
|
408
459
|
dict: resposta do ServiceNow
|
409
460
|
"""
|
410
461
|
if header_content_type is None:
|
411
|
-
header_content_type = self.__valida_header_content_type(
|
412
|
-
|
462
|
+
header_content_type = self.__valida_header_content_type(
|
463
|
+
anexo_path, header_content_type
|
464
|
+
)
|
465
|
+
|
413
466
|
try:
|
414
|
-
AttachFileTicketValidator(
|
467
|
+
AttachFileTicketValidator(
|
468
|
+
header_content_type=header_content_type,
|
469
|
+
anexo_path=anexo_path,
|
470
|
+
tabela=tabela,
|
471
|
+
sys_id=sys_id,
|
472
|
+
timeout=timeout,
|
473
|
+
)
|
415
474
|
except ValidationError as e:
|
416
|
-
raise ValueError(
|
417
|
-
|
475
|
+
raise ValueError(
|
476
|
+
"Erro na validação dos dados de input do método:", e.errors()
|
477
|
+
)
|
478
|
+
|
418
479
|
if not os.path.exists(anexo_path):
|
419
480
|
raise FileExistsError(f"O arquivo não foi encontrado ({anexo_path})")
|
420
481
|
|
421
|
-
|
422
|
-
|
423
482
|
# Converte as chaves do dicionário para minúsculas
|
424
|
-
header_content_type_lower = {
|
483
|
+
header_content_type_lower = {
|
484
|
+
k.lower(): v for k, v in header_content_type.items()
|
485
|
+
}
|
425
486
|
|
426
|
-
|
427
487
|
if "content-type" not in header_content_type_lower:
|
428
|
-
raise ValueError(
|
488
|
+
raise ValueError(
|
489
|
+
"O parâmetro 'header_content_type' não possui a chave 'Content-Type' com o tipo do anexo"
|
490
|
+
)
|
429
491
|
|
430
492
|
nome_arquivo = os.path.basename(anexo_path)
|
431
493
|
try:
|
432
|
-
with open(anexo_path,
|
494
|
+
with open(anexo_path, "rb") as f:
|
433
495
|
url = f"{self.api_url}/now/attachment/file?table_name={tabela}&table_sys_id={sys_id}&file_name={nome_arquivo}"
|
434
|
-
response = requests.post(
|
435
|
-
|
496
|
+
response = requests.post(
|
497
|
+
url,
|
498
|
+
headers=header_content_type,
|
499
|
+
auth=(self.__username, self.__password),
|
500
|
+
data=f,
|
501
|
+
timeout=timeout,
|
502
|
+
)
|
503
|
+
|
436
504
|
logging.debug("Arquivo adicionado no ticket")
|
437
|
-
return {"success": True, "result"
|
438
|
-
|
505
|
+
return {"success": True, "result": response}
|
506
|
+
|
439
507
|
except Exception as e:
|
440
|
-
return {"success"
|
441
|
-
|
508
|
+
return {"success": False, "result": None, "error": str(e)}
|
442
509
|
|
443
510
|
def __valida_header_content_type(self, anexo_path, header_content_type):
|
444
511
|
"""
|
@@ -460,35 +527,49 @@ class ServiceNow:
|
|
460
527
|
|
461
528
|
Observação:
|
462
529
|
- O parâmetro `header_content_type` é uma variável local utilizada para compor os cabeçalhos HTTP, contendo informações do tipo de conteúdo do arquivo.
|
463
|
-
|
530
|
+
|
464
531
|
"""
|
465
532
|
|
466
533
|
# Pré validando 'header_content_type'
|
467
|
-
if
|
468
|
-
|
534
|
+
if (
|
535
|
+
os.path.splitext(anexo_path)[1].lower() == ".zip"
|
536
|
+
and header_content_type is None
|
537
|
+
):
|
538
|
+
|
469
539
|
header_content_type = {"Content-Type": "application/zip"}
|
470
|
-
|
471
|
-
elif
|
472
|
-
|
473
|
-
header_content_type
|
474
|
-
|
475
|
-
|
476
|
-
|
540
|
+
|
541
|
+
elif (
|
542
|
+
os.path.splitext(anexo_path)[1].lower() == ".xlsx"
|
543
|
+
and header_content_type is None
|
544
|
+
):
|
545
|
+
|
546
|
+
header_content_type = {
|
547
|
+
"Content-Type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
548
|
+
}
|
549
|
+
|
550
|
+
elif (
|
551
|
+
os.path.splitext(anexo_path)[1].lower() == ".pdf"
|
552
|
+
and header_content_type is None
|
553
|
+
):
|
554
|
+
|
477
555
|
header_content_type = {"Content-Type": "application/pdf"}
|
478
|
-
|
479
|
-
elif
|
480
|
-
|
556
|
+
|
557
|
+
elif (
|
558
|
+
os.path.splitext(anexo_path)[1].lower() == ".txt"
|
559
|
+
and header_content_type is None
|
560
|
+
):
|
561
|
+
|
481
562
|
header_content_type = {"Content-Type": "text/plain"}
|
482
563
|
|
483
564
|
# Validação de 'header_content_type'
|
484
565
|
if not isinstance(header_content_type, dict):
|
485
|
-
raise ValueError(
|
486
|
-
|
487
|
-
|
488
|
-
return header_content_type
|
566
|
+
raise ValueError(
|
567
|
+
"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\"})"
|
568
|
+
)
|
489
569
|
|
570
|
+
return header_content_type
|
490
571
|
|
491
|
-
def download_anexo(self, sys_id_file
|
572
|
+
def download_anexo(self, sys_id_file: str, file_path: str, timeout: int = 15):
|
492
573
|
"""
|
493
574
|
Faz o download de um anexo do ServiceNow utilizando o `sys_id` do arquivo e salva no caminho especificado.
|
494
575
|
|
@@ -525,8 +606,10 @@ class ServiceNow:
|
|
525
606
|
try:
|
526
607
|
DownloadFileValidator(sys_id_file=sys_id_file, file_path=file_path)
|
527
608
|
except ValidationError as e:
|
528
|
-
raise ValueError(
|
529
|
-
|
609
|
+
raise ValueError(
|
610
|
+
"Erro na validação dos dados de input do método:", e.errors()
|
611
|
+
)
|
612
|
+
|
530
613
|
url = f"{self.api_url}/now/attachment/{sys_id_file}/file"
|
531
614
|
response = self.__request_download(url=url, timeout=timeout)
|
532
615
|
response = response.get("result")
|
@@ -537,50 +620,56 @@ class ServiceNow:
|
|
537
620
|
print(diretorio)
|
538
621
|
os.makedirs(diretorio, exist_ok=True)
|
539
622
|
logging.debug(f"Diretorio criado: {diretorio}")
|
540
|
-
with open(file_path,
|
623
|
+
with open(file_path, "wb") as f:
|
541
624
|
f.write(response.content)
|
542
|
-
return {"success"
|
543
|
-
|
625
|
+
return {"success": True, "path": file_path}
|
626
|
+
|
544
627
|
except FileNotFoundError:
|
545
628
|
try:
|
546
629
|
path = os.path.dirname(file_path)
|
547
630
|
os.makedirs(path)
|
548
|
-
with open(file_path,
|
631
|
+
with open(file_path, "wb") as f:
|
549
632
|
f.write(response.content)
|
550
|
-
return {"success"
|
633
|
+
return {"success": True, "path": file_path}
|
551
634
|
except Exception as e:
|
552
635
|
logging.debug(f"Erro ao salvar o arquivo. Erro: {e}")
|
553
|
-
return {"success"
|
636
|
+
return {"success": False, "error": str(e)}
|
554
637
|
except Exception as e:
|
555
638
|
logging.error(f"Erro ao salvar o arquivo. Erro: {e}")
|
556
|
-
return {"success"
|
639
|
+
return {"success": False, "error": str(e)}
|
557
640
|
else:
|
558
641
|
logging.debug(f"{response.status_code}")
|
559
|
-
return {"success"
|
642
|
+
return {"success": False, "error": f"Status code: {response.status_code }"}
|
560
643
|
|
561
|
-
def get_variables_from_ticket(self, sys_id
|
644
|
+
def get_variables_from_ticket(self, sys_id: str, campos: str = ""):
|
562
645
|
"""
|
563
646
|
Obtém as variáveis associadas ao ticket.
|
564
647
|
args:
|
565
648
|
sys_id : STR - Id do ticket
|
566
649
|
"""
|
567
650
|
if isinstance(campos, list):
|
568
|
-
campos =
|
651
|
+
campos = ",".join(campos)
|
569
652
|
if campos == "":
|
570
|
-
campos =
|
653
|
+
campos = "name,question_text,type,default_value, sys_id"
|
571
654
|
|
572
655
|
logging.debug(f"Obtendo variáveis do ticket {sys_id}")
|
573
656
|
url = f"{self.api_url}/now/table/item_option_new"
|
574
657
|
params = {
|
575
|
-
|
576
|
-
|
577
|
-
|
658
|
+
"sysparm_query": f"cat_item={sys_id}",
|
659
|
+
"sysparm_display_value": "true",
|
660
|
+
"sysparm_fields": campos,
|
578
661
|
}
|
579
662
|
response = self.request(url, params=params)
|
580
663
|
return response
|
581
|
-
|
582
664
|
|
583
|
-
def get_anexo(
|
665
|
+
def get_anexo(
|
666
|
+
self,
|
667
|
+
sys_id: str = None,
|
668
|
+
tabela: str = None,
|
669
|
+
campo: str = "default",
|
670
|
+
download_dir: str = None,
|
671
|
+
timeout: int = 15,
|
672
|
+
) -> dict:
|
584
673
|
"""Traz os anexos de um campo do ticket especificado
|
585
674
|
|
586
675
|
Args:
|
@@ -593,50 +682,57 @@ class ServiceNow:
|
|
593
682
|
dict: dicionário com os anexos do ticket
|
594
683
|
"""
|
595
684
|
try:
|
596
|
-
GetAttachValidator(
|
597
|
-
|
598
|
-
|
599
|
-
download_dir=download_dir)
|
685
|
+
GetAttachValidator(
|
686
|
+
sys_id=sys_id, tabela=tabela, timeout=timeout, download_dir=download_dir
|
687
|
+
)
|
600
688
|
except ValidationError as e:
|
601
|
-
raise ValueError(
|
602
|
-
|
689
|
+
raise ValueError(
|
690
|
+
"Erro na validação dos dados de input do método:", e.errors()
|
691
|
+
)
|
692
|
+
|
603
693
|
if download_dir is not None:
|
604
694
|
if not isinstance(download_dir, str) or not download_dir.strip():
|
605
|
-
raise ValueError(
|
606
|
-
|
607
|
-
|
608
|
-
|
695
|
+
raise ValueError(
|
696
|
+
"O parâmetro 'download_dir' precisa ser a pasta pra onde o anexo será feito o download."
|
697
|
+
)
|
698
|
+
if not os.path.exists(download_dir):
|
699
|
+
raise NotADirectoryError(
|
700
|
+
f"A pasta informada '{download_dir}' não existe"
|
701
|
+
)
|
702
|
+
|
609
703
|
# Validação de 'campo'
|
610
704
|
if not isinstance(campo, str) or not campo.strip():
|
611
|
-
raise ValueError(
|
705
|
+
raise ValueError(
|
706
|
+
"O parâmetro 'campo' precisa ser uma string não vazia com o nome do campo do anexo."
|
707
|
+
)
|
612
708
|
|
613
709
|
campo = str(campo).strip().lower()
|
614
710
|
|
615
711
|
# Convert bytes to base64
|
616
712
|
def __bytes_to_base64(image_bytes):
|
617
713
|
|
618
|
-
return base64.b64encode(image_bytes).decode(
|
619
|
-
|
714
|
+
return base64.b64encode(image_bytes).decode("utf-8")
|
715
|
+
|
620
716
|
def __formatar_tamanho(tamanho_bytes):
|
621
717
|
# Converte o valor de string para inteiro
|
622
718
|
tamanho_bytes = int(tamanho_bytes)
|
623
|
-
|
719
|
+
|
624
720
|
# Define os múltiplos de bytes
|
625
|
-
unidades = [
|
721
|
+
unidades = ["B", "KB", "MB", "GB", "TB"]
|
626
722
|
|
627
723
|
# Itera sobre as unidades até encontrar a maior possível
|
628
724
|
for unidade in unidades:
|
629
725
|
if tamanho_bytes < 1024:
|
630
726
|
return f"{tamanho_bytes:.2f} {unidade}"
|
631
727
|
tamanho_bytes /= 1024
|
632
|
-
|
728
|
+
|
633
729
|
# Caso o valor seja maior que o esperado (Exabyte ou superior)
|
634
730
|
return f"{tamanho_bytes:.2f} PB" # Petabyte
|
635
731
|
|
636
|
-
anexo_dict = {"var_servicenow": campo, "anexos":[]}
|
637
|
-
|
732
|
+
anexo_dict = {"var_servicenow": campo, "anexos": []}
|
733
|
+
|
638
734
|
try:
|
639
|
-
if campo ==
|
735
|
+
if campo == "default":
|
640
736
|
url = f"{self.api_url}/now/attachment?sysparm_query=table_name={tabela}^table_sys_id={sys_id}"
|
641
737
|
response = self.__request_download(url, timeout=timeout)
|
642
738
|
response = response.get("result")
|
@@ -646,18 +742,27 @@ class ServiceNow:
|
|
646
742
|
"file_name": attachment["file_name"],
|
647
743
|
"size": __formatar_tamanho(attachment["size_bytes"]),
|
648
744
|
"content_type": attachment["content_type"],
|
649
|
-
"base64": None
|
745
|
+
"base64": None,
|
650
746
|
}
|
651
|
-
byte_response = self.__request_download(
|
747
|
+
byte_response = self.__request_download(
|
748
|
+
attachment["download_link"], timeout=timeout
|
749
|
+
)
|
652
750
|
byte_response = byte_response.get("result")
|
653
751
|
if byte_response.status_code == 200:
|
654
752
|
arquivo["base64"] = __bytes_to_base64(byte_response.content)
|
655
753
|
if download_dir:
|
656
|
-
with open(
|
754
|
+
with open(
|
755
|
+
os.path.join(download_dir, arquivo["file_name"]),
|
756
|
+
"wb",
|
757
|
+
) as f:
|
657
758
|
f.write(byte_response.content)
|
658
759
|
anexo_dict["anexos"].append(arquivo)
|
659
760
|
return {"success": True, "result": anexo_dict}
|
660
|
-
return {
|
761
|
+
return {
|
762
|
+
"success": False,
|
763
|
+
"error": response.json(),
|
764
|
+
"status_code": response.status_code,
|
765
|
+
}
|
661
766
|
|
662
767
|
else:
|
663
768
|
url = f"{self.api_url}/now/table/{tabela}?sysparm_query=sys_id={sys_id}&sysparm_fields={campo}&sysparm_display_value=all"
|
@@ -667,23 +772,38 @@ class ServiceNow:
|
|
667
772
|
campo_data = response.json()["result"][0].get(campo)
|
668
773
|
if campo_data:
|
669
774
|
attachment_id = campo_data["value"]
|
670
|
-
attachment_url =
|
671
|
-
|
775
|
+
attachment_url = (
|
776
|
+
f"{self.api_url}/now/attachment/{attachment_id}/file"
|
777
|
+
)
|
778
|
+
byte_response = self.__request_download(
|
779
|
+
attachment["download_link"], timeout=timeout
|
780
|
+
)
|
672
781
|
byte_response = byte_response.get("result")
|
673
782
|
if byte_response.status_code == 200:
|
674
783
|
arquivo = {
|
675
784
|
"file_name": campo_data["display_value"],
|
676
|
-
"size": __formatar_tamanho(
|
677
|
-
|
678
|
-
|
785
|
+
"size": __formatar_tamanho(
|
786
|
+
byte_response.headers.get("Content-Length", 0)
|
787
|
+
),
|
788
|
+
"content_type": byte_response.headers.get(
|
789
|
+
"Content-Type"
|
790
|
+
),
|
791
|
+
"base64": __bytes_to_base64(byte_response.content),
|
679
792
|
}
|
680
793
|
if download_dir:
|
681
|
-
with open(
|
794
|
+
with open(
|
795
|
+
os.path.join(download_dir, arquivo["file_name"]),
|
796
|
+
"wb",
|
797
|
+
) as f:
|
682
798
|
f.write(byte_response.content)
|
683
799
|
anexo_dict["anexos"].append(arquivo)
|
684
|
-
return {"success": True, "result": anexo_dict, "error"
|
685
|
-
return {
|
800
|
+
return {"success": True, "result": anexo_dict, "error": None}
|
801
|
+
return {
|
802
|
+
"success": False,
|
803
|
+
"error": response.json(),
|
804
|
+
"status_code": response.status_code,
|
805
|
+
}
|
686
806
|
|
687
807
|
except Exception as e:
|
688
808
|
logging.debug("Erro ao obter anexos.")
|
689
|
-
return {"success": False, "error": str(e)}
|
809
|
+
return {"success": False, "error": str(e)}
|
@@ -33,6 +33,7 @@ class WebScreenBotCity(WebScreenAbstract):
|
|
33
33
|
no_sandbox: bool = True,
|
34
34
|
timeout: int = 10,
|
35
35
|
security: bool = False,
|
36
|
+
download_path: str = "./tmp/",
|
36
37
|
):
|
37
38
|
"""
|
38
39
|
Inicializa a classe com as configurações para o WebBot.
|
@@ -65,6 +66,7 @@ class WebScreenBotCity(WebScreenAbstract):
|
|
65
66
|
self.web_bot.headless = headless
|
66
67
|
self.web_bot.disable_gpu = disable_gpu
|
67
68
|
self.web_bot.no_sandbox = no_sandbox
|
69
|
+
self.web_bot.download_folder_path = download_path
|
68
70
|
|
69
71
|
except Exception as e:
|
70
72
|
raise ValueError("Erro na inicialização da classe:", e)
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import time
|
2
|
+
import os
|
2
3
|
|
3
4
|
# Selenium
|
4
5
|
from selenium import webdriver
|
5
6
|
from selenium.webdriver.common.by import By
|
6
7
|
from selenium.webdriver.common.keys import Keys
|
7
|
-
from webdriver_manager.chrome import ChromeDriverManager
|
8
8
|
from selenium.webdriver.support.ui import WebDriverWait
|
9
9
|
from selenium.webdriver.common.action_chains import ActionChains
|
10
10
|
from selenium.webdriver.support import expected_conditions as EC
|
@@ -39,6 +39,7 @@ class WebScreenSelenium(WebScreenAbstract):
|
|
39
39
|
timeout: int = 10,
|
40
40
|
security: bool = False,
|
41
41
|
scale: float = 0.8,
|
42
|
+
download_path: str = "./tmp/",
|
42
43
|
):
|
43
44
|
"""
|
44
45
|
Inicializa a classe responsável por configurar e gerenciar o WebDriver do Selenium.
|
@@ -96,6 +97,16 @@ class WebScreenSelenium(WebScreenAbstract):
|
|
96
97
|
chrome_options.add_argument("--disable-extensions")
|
97
98
|
chrome_options.add_argument("--window-size=1920,1080")
|
98
99
|
chrome_options.add_argument(f"--force-device-scale-factor={scale}")
|
100
|
+
os.makedirs(download_path, exist_ok=True)
|
101
|
+
chrome_options.add_experimental_option(
|
102
|
+
"prefs",
|
103
|
+
{
|
104
|
+
"download.default_directory": os.path.abspath(download_path),
|
105
|
+
"download.prompt_for_download": False, # Não perguntar onde salvar
|
106
|
+
"directory_upgrade": True,
|
107
|
+
"safebrowsing.enabled": True, # Para evitar bloqueios do Chrome
|
108
|
+
},
|
109
|
+
)
|
99
110
|
|
100
111
|
chrome_options.add_argument(
|
101
112
|
"user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36"
|
csc_cia_stne/web.py
CHANGED
@@ -16,6 +16,7 @@ class web_screen:
|
|
16
16
|
disable_gpu: bool = True,
|
17
17
|
no_sandbox: bool = True,
|
18
18
|
security: bool = True,
|
19
|
+
download_path: str = "./tmp/",
|
19
20
|
):
|
20
21
|
"""
|
21
22
|
Inicializa a instância da classe Web.
|
@@ -59,6 +60,7 @@ class web_screen:
|
|
59
60
|
no_sandbox=no_sandbox,
|
60
61
|
timeout=timeout,
|
61
62
|
security=security,
|
63
|
+
download_path=download_path,
|
62
64
|
)
|
63
65
|
if model.upper() == "SELENIUM"
|
64
66
|
else WebScreenBotCity(
|
@@ -67,5 +69,6 @@ class web_screen:
|
|
67
69
|
no_sandbox=no_sandbox,
|
68
70
|
timeout=timeout,
|
69
71
|
security=security,
|
72
|
+
download_path=download_path,
|
70
73
|
)
|
71
74
|
)
|
@@ -5,16 +5,16 @@ csc_cia_stne/email.py,sha256=K0DcgxTPKa_Rz_SJekjbW8Nw_1L9s_iuDDxZ-69bZfM,8387
|
|
5
5
|
csc_cia_stne/ftp.py,sha256=M9WCaq2hm56jGyszNaPinliFaZS0BNrT7VrVPMjkMg4,10988
|
6
6
|
csc_cia_stne/gcp_bigquery.py,sha256=foq8azvvv_f7uikMDslX9RcUIrx7RAS-Sn0AGW0QFQc,7231
|
7
7
|
csc_cia_stne/gcp_bucket.py,sha256=nP77BtagZ7jQq6lS88ZEa1qshzBza6e_LvhgS3_JJJk,10268
|
8
|
-
csc_cia_stne/google_drive.py,sha256=
|
8
|
+
csc_cia_stne/google_drive.py,sha256=VOaI_ZehDTqqNqk5aVqaU4g6yz_ClsPLYArqgg6-SPs,16348
|
9
9
|
csc_cia_stne/karavela.py,sha256=jJCYX43D49gGuzmwwK6bN9XVnv2dXdp9iHnnV5H1LMQ,4794
|
10
10
|
csc_cia_stne/logger_json.py,sha256=CXxSCOFGMymDi8XE9SKnPKjW4D0wJLqDLnxqePS26i8,3187
|
11
11
|
csc_cia_stne/logger_rich.py,sha256=fklgkBb4rblKQd7YZ3q-eWfhGg9eflO2k2-z4pGh_yo,5201
|
12
12
|
csc_cia_stne/provio.py,sha256=G-pDnHYLSp97joc7S7dvwjNvl3omnTmvdi3rOPQf5GA,3987
|
13
|
-
csc_cia_stne/servicenow.py,sha256=
|
13
|
+
csc_cia_stne/servicenow.py,sha256=2AeG9icBOjwKVVmGbcJvM2mPEFFzYSA1pN1qJYbnM2c,33721
|
14
14
|
csc_cia_stne/slack.py,sha256=sPLeaQh_JewLcrBDjjwUgbjtC7d1Np03OTy06JimMV4,8117
|
15
15
|
csc_cia_stne/stne_admin.py,sha256=4v_BVQAwZeWmxvjDOkwFAl9yIxJ3r54BY7pRgAgSXEM,24220
|
16
16
|
csc_cia_stne/wacess.py,sha256=g-bWZNpm_tU7UsW1G_rqh_2fW2KShvxZHGOerX8DuQw,26768
|
17
|
-
csc_cia_stne/web.py,sha256=
|
17
|
+
csc_cia_stne/web.py,sha256=TBXUJ5eS36fytU3oFDuJsogi0sgw_qKgK-uphx4Nvxo,2506
|
18
18
|
csc_cia_stne/utilitarios/__init__.py,sha256=eUaRttjY-F_zHAHC3L22VZxWyQd_k9zso-Mjz01Rj9o,306
|
19
19
|
csc_cia_stne/utilitarios/functions/__init__.py,sha256=tBN1a6ZlvS1kLXIGopaqecJvlkOhLvLeYjp3JCAspWs,471
|
20
20
|
csc_cia_stne/utilitarios/functions/func_b64.py,sha256=XGU34BIQQXWXBS0yM2B4A2wDlcrMl1unIJXjq4lpLnk,1254
|
@@ -34,10 +34,10 @@ csc_cia_stne/utilitarios/validations/waccess.py,sha256=8yfOrmIPUSLzbCt6P0F6vj3Fk
|
|
34
34
|
csc_cia_stne/utilitarios/validations/web_validator.py,sha256=HYKYSpDv1RvRjZIuwTPt-AbEz-9392MxM_O329iYuSA,5722
|
35
35
|
csc_cia_stne/utilitarios/web_screen/__init__.py,sha256=5QcOPXKd95SvP2DoZiHS0gaU68GlyFD9pQ9kae_9D1Q,100
|
36
36
|
csc_cia_stne/utilitarios/web_screen/web_screen_abstract.py,sha256=PjL8Vgfj_JdKidia7RFyCkro3avYLQu4RZRos41sh3w,3241
|
37
|
-
csc_cia_stne/utilitarios/web_screen/web_screen_botcity.py,sha256=
|
38
|
-
csc_cia_stne/utilitarios/web_screen/web_screen_selenium.py,sha256=
|
39
|
-
csc_cia_stne-0.1.
|
40
|
-
csc_cia_stne-0.1.
|
41
|
-
csc_cia_stne-0.1.
|
42
|
-
csc_cia_stne-0.1.
|
43
|
-
csc_cia_stne-0.1.
|
37
|
+
csc_cia_stne/utilitarios/web_screen/web_screen_botcity.py,sha256=Xi5YJjl2pcxlX3OimqcBWRNXZEpAE7asyUjDJ4Oho5U,12297
|
38
|
+
csc_cia_stne/utilitarios/web_screen/web_screen_selenium.py,sha256=JLIcPJE9ZX3Pd6zG6oTRMqqUAY063UzLY3ReRlxmiSM,15581
|
39
|
+
csc_cia_stne-0.1.3.dist-info/licenses/LICENCE,sha256=LPGMtgKki2C3KEZP7hDhA1HBrlq5JCHkIeStUCLEMx4,1073
|
40
|
+
csc_cia_stne-0.1.3.dist-info/METADATA,sha256=9m7R6yZRqbL9ozjOe7vBBzsSh_uyiPnlftqacP0jDUY,1418
|
41
|
+
csc_cia_stne-0.1.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
42
|
+
csc_cia_stne-0.1.3.dist-info/top_level.txt,sha256=ldo7GVv3tQx5KJvwBzdZzzQmjPys2NDVVn1rv0BOF2Q,13
|
43
|
+
csc_cia_stne-0.1.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|