io4it 3.0.3.2__tar.gz → 3.0.4__tar.gz
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.
- {io4it-3.0.3.2 → io4it-3.0.4}/PKG-INFO +1 -1
- {io4it-3.0.3.2 → io4it-3.0.4}/io4it.egg-info/PKG-INFO +1 -1
- {io4it-3.0.3.2 → io4it-3.0.4}/io4it.egg-info/SOURCES.txt +4 -1
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/utils/keys_manager.py +138 -13
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/utils/mail.py +11 -95
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWExportMarkdown.py +12 -9
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWExtractTablesDocxToXlsx.py +47 -43
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWInboxMailMonitoring.py +9 -5
- io4it-3.0.4/orangecontrib/IO4IT/widgets/OWJsonToDataTable.py +80 -0
- io4it-3.0.3.2/orangecontrib/IO4IT/widgets/designer/owdocxtoxlsx.ui → io4it-3.0.4/orangecontrib/IO4IT/widgets/designer/ow_extract_tables_docx_to_xlsx.ui +34 -44
- io4it-3.0.4/orangecontrib/IO4IT/widgets/designer/ow_json_to_data_table.ui +138 -0
- io4it-3.0.4/orangecontrib/IO4IT/widgets/icons/json-file.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/setup.py +1 -1
- {io4it-3.0.3.2 → io4it-3.0.4}/io4it.egg-info/dependency_links.txt +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/io4it.egg-info/entry_points.txt +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/io4it.egg-info/namespace_packages.txt +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/io4it.egg-info/requires.txt +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/io4it.egg-info/top_level.txt +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/__init__.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/ocr_function/__init__.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/ocr_function/word_converter.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/utils/__init__.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/utils/pool_exec_utils.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/utils/secret_manager.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/utils/utils_md.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWChatGpt.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWDeep_Search.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWDoclingASR.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWDoclingToMarkdown.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWMD2HTML.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWMarkdownLoader.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWMarkdownizer.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWOfficeNormalizer.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWParserHTML.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWPdfType.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWProcessPoolExecutor.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWS3Uploader.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWS3downloader.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWS3list.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWSpeechToText.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWWebSearch.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWmailLoader.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWmailSender.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/OWwordpdf2docx.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/__init__.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/__init__.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/nogui.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/ow_file_ext_selector.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/owchatgpt.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/owdeepsearch.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/owdoclingasr.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/owdoclingtomarkdown.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/owexportmarkdown.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/owinboxmailmonitoring.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/owmailloader.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/owmailsender.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/owmarkdownizer.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/owmarkdownloader.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/owmd2html.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/owofficenormalizer.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/owparserhtml.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/owpdftype.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/owprocesspoolexecutor.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/owspeechtotext.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/owvisualizationer.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/owwebsearch.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/designer/wordpdf2docx.ui +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/__init__.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/chatgpt.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/check_pdf.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/deepsearch.svg +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/dep_md_old.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/download.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/export_md.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/extract_table.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/file_extensor.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/html.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/list_aws.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/load_md.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/mail_loader.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/mail_writer.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/md.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/monitor-email.svg +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/office_normalizer.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/owmd2html.svg +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/process_pool_executor.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/speech_to_text.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/upload.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/visualizationer.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/websearch.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons/wordpdf2docx.png +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/IO4IT/widgets/icons_dev/__init__.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/orangecontrib/__init__.py +0 -0
- {io4it-3.0.3.2 → io4it-3.0.4}/setup.cfg +0 -0
|
@@ -23,6 +23,7 @@ orangecontrib/IO4IT/widgets/OWDoclingToMarkdown.py
|
|
|
23
23
|
orangecontrib/IO4IT/widgets/OWExportMarkdown.py
|
|
24
24
|
orangecontrib/IO4IT/widgets/OWExtractTablesDocxToXlsx.py
|
|
25
25
|
orangecontrib/IO4IT/widgets/OWInboxMailMonitoring.py
|
|
26
|
+
orangecontrib/IO4IT/widgets/OWJsonToDataTable.py
|
|
26
27
|
orangecontrib/IO4IT/widgets/OWMD2HTML.py
|
|
27
28
|
orangecontrib/IO4IT/widgets/OWMarkdownLoader.py
|
|
28
29
|
orangecontrib/IO4IT/widgets/OWMarkdownizer.py
|
|
@@ -41,12 +42,13 @@ orangecontrib/IO4IT/widgets/OWwordpdf2docx.py
|
|
|
41
42
|
orangecontrib/IO4IT/widgets/__init__.py
|
|
42
43
|
orangecontrib/IO4IT/widgets/designer/__init__.py
|
|
43
44
|
orangecontrib/IO4IT/widgets/designer/nogui.ui
|
|
45
|
+
orangecontrib/IO4IT/widgets/designer/ow_extract_tables_docx_to_xlsx.ui
|
|
44
46
|
orangecontrib/IO4IT/widgets/designer/ow_file_ext_selector.ui
|
|
47
|
+
orangecontrib/IO4IT/widgets/designer/ow_json_to_data_table.ui
|
|
45
48
|
orangecontrib/IO4IT/widgets/designer/owchatgpt.ui
|
|
46
49
|
orangecontrib/IO4IT/widgets/designer/owdeepsearch.ui
|
|
47
50
|
orangecontrib/IO4IT/widgets/designer/owdoclingasr.ui
|
|
48
51
|
orangecontrib/IO4IT/widgets/designer/owdoclingtomarkdown.ui
|
|
49
|
-
orangecontrib/IO4IT/widgets/designer/owdocxtoxlsx.ui
|
|
50
52
|
orangecontrib/IO4IT/widgets/designer/owexportmarkdown.ui
|
|
51
53
|
orangecontrib/IO4IT/widgets/designer/owinboxmailmonitoring.ui
|
|
52
54
|
orangecontrib/IO4IT/widgets/designer/owmailloader.ui
|
|
@@ -72,6 +74,7 @@ orangecontrib/IO4IT/widgets/icons/export_md.png
|
|
|
72
74
|
orangecontrib/IO4IT/widgets/icons/extract_table.png
|
|
73
75
|
orangecontrib/IO4IT/widgets/icons/file_extensor.png
|
|
74
76
|
orangecontrib/IO4IT/widgets/icons/html.png
|
|
77
|
+
orangecontrib/IO4IT/widgets/icons/json-file.png
|
|
75
78
|
orangecontrib/IO4IT/widgets/icons/list_aws.png
|
|
76
79
|
orangecontrib/IO4IT/widgets/icons/load_md.png
|
|
77
80
|
orangecontrib/IO4IT/widgets/icons/mail_loader.png
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import re
|
|
2
3
|
import json
|
|
3
4
|
import hashlib
|
|
4
5
|
import getpass
|
|
@@ -11,6 +12,21 @@ else:
|
|
|
11
12
|
from orangecontrib.AAIT.utils import MetManagement
|
|
12
13
|
from orangecontrib.IO4IT.utils import secret_manager
|
|
13
14
|
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _normalize_single_quotes_json(s: str) -> str:
|
|
18
|
+
"""
|
|
19
|
+
Convertit un pseudo-JSON avec quotes simples
|
|
20
|
+
en JSON valide, de manière contrôlée.
|
|
21
|
+
"""
|
|
22
|
+
# ⚠️ On ne touche qu'aux clés et valeurs simples
|
|
23
|
+
# 'key': 'value' → "key": "value"
|
|
24
|
+
s = re.sub(r"'([^']*)'\s*:", r'"\1":', s)
|
|
25
|
+
s = re.sub(r":\s*'([^']*)'", r': "\1"', s)
|
|
26
|
+
return s
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
14
30
|
def ask_secure():
|
|
15
31
|
while True:
|
|
16
32
|
resp = input("Secure? (Y/N) : ").strip().lower()
|
|
@@ -240,6 +256,25 @@ def enregistrer_config_owa_secure(mail, alias, server, username, password, inter
|
|
|
240
256
|
|
|
241
257
|
|
|
242
258
|
|
|
259
|
+
|
|
260
|
+
def lire_config_imap4_ssl_dict_sec(chemin_fichier):
|
|
261
|
+
if len(chemin_fichier)<5:
|
|
262
|
+
print(f"❌ Error path not correct", chemin_fichier)
|
|
263
|
+
return None
|
|
264
|
+
if not chemin_fichier.endswith(".sec"):
|
|
265
|
+
chemin_fichier += ".sec"
|
|
266
|
+
try:
|
|
267
|
+
service = "IMAP4_SSL__" + chemin_fichier[:-4]
|
|
268
|
+
sm = secret_manager.SecretManager(service)
|
|
269
|
+
contenu = sm.load_all()
|
|
270
|
+
return contenu
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
except Exception as e:
|
|
274
|
+
print(f"❌ Erreur lors de la lecture : {e}")
|
|
275
|
+
return None
|
|
276
|
+
|
|
277
|
+
|
|
243
278
|
# Fonction pour lire le fichier de configuration et déchiffrer le mot de passe
|
|
244
279
|
def lire_config_imap4_ssl(chemin_fichier):
|
|
245
280
|
# renvoie une liste =["agent","domain",mdp,"interval_second"]
|
|
@@ -251,6 +286,7 @@ def lire_config_imap4_ssl(chemin_fichier):
|
|
|
251
286
|
service = "IMAP4_SSL__" + chemin_fichier[:-4]
|
|
252
287
|
sm = secret_manager.SecretManager(service)
|
|
253
288
|
contenu = sm.load_all()
|
|
289
|
+
print(contenu)
|
|
254
290
|
return [
|
|
255
291
|
contenu["agent"],
|
|
256
292
|
contenu["domain"],
|
|
@@ -284,14 +320,30 @@ def lire_config_imap4_ssl(chemin_fichier):
|
|
|
284
320
|
print(f"❌ Erreur lors de la lecture : {e}")
|
|
285
321
|
return None
|
|
286
322
|
|
|
287
|
-
def
|
|
323
|
+
def lire_config_oauth2_dict_sec(chemin_fichier, type="MICROSOFT_EXCHANGE_OAUTH2"):
|
|
324
|
+
# renvoie une liste =["agent","domain",mdp,"interval_second"]
|
|
325
|
+
if len(chemin_fichier) < 5:
|
|
326
|
+
print(f"❌ Error path not correct", chemin_fichier)
|
|
327
|
+
return None
|
|
328
|
+
if not chemin_fichier.endswith(".sec"):
|
|
329
|
+
chemin_fichier+=".sec"
|
|
330
|
+
try:
|
|
331
|
+
service = type + "__" + chemin_fichier[:-4]
|
|
332
|
+
sm = secret_manager.SecretManager(service)
|
|
333
|
+
contenu = sm.load_all()
|
|
334
|
+
return contenu
|
|
335
|
+
except Exception as e:
|
|
336
|
+
print(f"❌ Erreur lors de la lecture : {e}")
|
|
337
|
+
return None
|
|
338
|
+
|
|
339
|
+
def lire_config_oauth2(chemin_fichier, type="MICROSOFT_EXCHANGE_OAUTH2"):
|
|
288
340
|
# renvoie une liste =["agent","domain",mdp,"interval_second"]
|
|
289
341
|
if len(chemin_fichier) < 5:
|
|
290
342
|
print(f"❌ Error path not correct", chemin_fichier)
|
|
291
343
|
return None
|
|
292
344
|
if chemin_fichier.endswith(".sec"):
|
|
293
345
|
try:
|
|
294
|
-
service = "
|
|
346
|
+
service = type + "__" + chemin_fichier[:-4]
|
|
295
347
|
sm = secret_manager.SecretManager(service)
|
|
296
348
|
contenu = sm.load_all()
|
|
297
349
|
return [
|
|
@@ -305,7 +357,7 @@ def lire_config_oauth2(chemin_fichier):
|
|
|
305
357
|
print(f"❌ Erreur lors de la lecture : {e}")
|
|
306
358
|
return None
|
|
307
359
|
try:
|
|
308
|
-
chemin_fichier = os.path.join(get_keys_dir(
|
|
360
|
+
chemin_fichier = os.path.join(get_keys_dir(type), chemin_fichier)
|
|
309
361
|
# Lecture du fichier JSON
|
|
310
362
|
with open(chemin_fichier, "r", encoding="utf-8") as f:
|
|
311
363
|
contenu = json.load(f)
|
|
@@ -327,6 +379,21 @@ def lire_config_oauth2(chemin_fichier):
|
|
|
327
379
|
print(f"❌ Erreur lors de la lecture : {e}")
|
|
328
380
|
return None
|
|
329
381
|
|
|
382
|
+
def lire_config_owa_dict_sec(chemin_fichier):
|
|
383
|
+
if len(chemin_fichier)<5:
|
|
384
|
+
print(f"❌ Error path not correct", chemin_fichier)
|
|
385
|
+
return None
|
|
386
|
+
if not chemin_fichier.endswith(".sec"):
|
|
387
|
+
chemin_fichier += ".sec"
|
|
388
|
+
try:
|
|
389
|
+
service="MICROSOFT_EXCHANGE_OWA__"+chemin_fichier[:-4]
|
|
390
|
+
sm = secret_manager.SecretManager(service)
|
|
391
|
+
contenu = sm.load_all()
|
|
392
|
+
return contenu
|
|
393
|
+
|
|
394
|
+
except Exception as e:
|
|
395
|
+
print(f"❌ Erreur lors de la lecture : {e}")
|
|
396
|
+
return None
|
|
330
397
|
|
|
331
398
|
|
|
332
399
|
def lire_config_owa(chemin_fichier):
|
|
@@ -412,15 +479,15 @@ def enregistrer_config_cli_owa():
|
|
|
412
479
|
if 0 != enregistrer_config_owa_secure(mail, alias, server, username, mdp, interval):
|
|
413
480
|
print("erreur!")
|
|
414
481
|
|
|
415
|
-
def enregistrer_config_oauth2_secure(client_id, client_secret, tenant_id, user_email):
|
|
416
|
-
dossier = get_keys_dir(
|
|
482
|
+
def enregistrer_config_oauth2_secure(client_id, client_secret, tenant_id, user_email, type="MICROSOFT_EXCHANGE_OAUTH2"):
|
|
483
|
+
dossier = get_keys_dir(type)
|
|
417
484
|
# Crée le dossier s'il n'existe pas
|
|
418
485
|
if not os.path.exists(dossier):
|
|
419
486
|
os.makedirs(dossier)
|
|
420
487
|
|
|
421
488
|
# Nom du fichier (remplace @ par _at_ pour éviter les problèmes)
|
|
422
489
|
nom_fichier = os.path.join(dossier, f"{user_email.replace('@', '_at_')}.sec")
|
|
423
|
-
service_name = f"
|
|
490
|
+
service_name = f"{type}__{user_email.replace('@', '_at_')}"
|
|
424
491
|
key = get_user_key()
|
|
425
492
|
|
|
426
493
|
contenu = {
|
|
@@ -440,8 +507,8 @@ def enregistrer_config_oauth2_secure(client_id, client_secret, tenant_id, user_e
|
|
|
440
507
|
return 0
|
|
441
508
|
|
|
442
509
|
|
|
443
|
-
def enregistrer_config_oauth2(client_id, client_secret, tenant_id, user_email):
|
|
444
|
-
dossier = get_keys_dir(
|
|
510
|
+
def enregistrer_config_oauth2(client_id, client_secret, tenant_id, user_email, type="MICROSOFT_EXCHANGE_OAUTH2"):
|
|
511
|
+
dossier = get_keys_dir(type)
|
|
445
512
|
# Crée le dossier s'il n'existe pas
|
|
446
513
|
if not os.path.exists(dossier):
|
|
447
514
|
os.makedirs(dossier)
|
|
@@ -472,27 +539,32 @@ def enregistrer_config_oauth2(client_id, client_secret, tenant_id, user_email):
|
|
|
472
539
|
|
|
473
540
|
def enregistrer_config_cli_oauth2():
|
|
474
541
|
print("\n📝 Écriture d’un fichier de configuration OAuth2 :")
|
|
542
|
+
type = input(
|
|
543
|
+
"📄 Nom du service à choisir entre MICROSOFT_EXCHANGE_OAUTH2 et MICROSOFT_EXCHANGE_OAUTH2_MICROSOFT_GRAPH : ").strip()
|
|
475
544
|
client_id = input("🆔 Client ID : ").strip()
|
|
476
545
|
client_secret = input("🔑 Client Secret : ").strip()
|
|
477
546
|
tenant_id = input("🏢 Tenant ID (GUID Azure) : ").strip()
|
|
478
547
|
user_email = input("📨 Adresse email de l'utilisateur Exchange : ").strip()
|
|
479
548
|
store = ask_secure()
|
|
480
549
|
if not store:
|
|
481
|
-
if 0 != enregistrer_config_oauth2(client_id, client_secret, tenant_id, user_email):
|
|
550
|
+
if 0 != enregistrer_config_oauth2(client_id, client_secret, tenant_id, user_email, type):
|
|
482
551
|
print("erreur!")
|
|
483
552
|
return
|
|
484
|
-
if 0 != enregistrer_config_oauth2_secure(client_id, client_secret, tenant_id, user_email):
|
|
553
|
+
if 0 != enregistrer_config_oauth2_secure(client_id, client_secret, tenant_id, user_email, type):
|
|
485
554
|
print("erreur!")
|
|
486
555
|
|
|
487
556
|
|
|
488
557
|
|
|
489
558
|
|
|
490
|
-
def lire_config_cli_oauth2():
|
|
559
|
+
def lire_config_cli_oauth2(type=""):
|
|
560
|
+
if type == "":
|
|
561
|
+
type = input("📄 Nom du service à choisir entre MICROSOFT_EXCHANGE_OAUTH2 et MICROSOFT_EXCHANGE_OAUTH2_MICROSOFT_GRAPH : ").strip()
|
|
491
562
|
chemin_fichier = input("📄 nom fichier json (pas le chemin!) JSON : ").strip()
|
|
492
|
-
|
|
563
|
+
print("oeoeo ", chemin_fichier, type)
|
|
564
|
+
config = lire_config_oauth2(chemin_fichier, type)
|
|
493
565
|
if config == None:
|
|
494
566
|
print("erreur")
|
|
495
|
-
|
|
567
|
+
|
|
496
568
|
|
|
497
569
|
|
|
498
570
|
|
|
@@ -539,6 +611,59 @@ def enregistrer_config_api(service_name, api_key, description=""):
|
|
|
539
611
|
print(f"❌ Erreur d’enregistrement : {e}")
|
|
540
612
|
return 1
|
|
541
613
|
|
|
614
|
+
|
|
615
|
+
def parse_json_and_save_api(config_str: str) -> None:
|
|
616
|
+
raw = config_str.strip()
|
|
617
|
+
|
|
618
|
+
# 1️⃣ Parsing initial
|
|
619
|
+
try:
|
|
620
|
+
data = json.loads(raw)
|
|
621
|
+
except json.JSONDecodeError as e:
|
|
622
|
+
# 2️⃣ Cas très courant : quotes simples
|
|
623
|
+
if "double quotes" in e.msg.lower():
|
|
624
|
+
try:
|
|
625
|
+
normalized = _normalize_single_quotes_json(raw)
|
|
626
|
+
data = json.loads(normalized)
|
|
627
|
+
except json.JSONDecodeError:
|
|
628
|
+
raise ValueError(
|
|
629
|
+
"Invalid JSON: use double quotes "
|
|
630
|
+
'(example: {"service": "xxx"})'
|
|
631
|
+
) from None
|
|
632
|
+
else:
|
|
633
|
+
raise ValueError(f"Invalid JSON syntax: {e.msg}") from None
|
|
634
|
+
|
|
635
|
+
# 3️⃣ Type attendu
|
|
636
|
+
if not isinstance(data, dict):
|
|
637
|
+
raise TypeError("JSON root must be an object")
|
|
638
|
+
|
|
639
|
+
# 4️⃣ Champs obligatoires
|
|
640
|
+
required_keys = ("service", "api_key")
|
|
641
|
+
missing = [k for k in required_keys if k not in data]
|
|
642
|
+
if missing:
|
|
643
|
+
raise ValueError(f"Missing required key(s): {', '.join(missing)}")
|
|
644
|
+
|
|
645
|
+
# 5️⃣ Validation stricte
|
|
646
|
+
for key in required_keys:
|
|
647
|
+
if not isinstance(data[key], str):
|
|
648
|
+
raise TypeError(f"'{key}' must be a string")
|
|
649
|
+
if not data[key].strip():
|
|
650
|
+
raise ValueError(f"'{key}' must be a non-empty string")
|
|
651
|
+
|
|
652
|
+
# 6️⃣ Champ optionnel
|
|
653
|
+
desc = data.get("description", "")
|
|
654
|
+
if not isinstance(desc, str):
|
|
655
|
+
raise TypeError("'description' must be a string")
|
|
656
|
+
|
|
657
|
+
# 7️⃣ Appel sécurisé
|
|
658
|
+
enregistrer_config_api_secure(
|
|
659
|
+
data["service"],
|
|
660
|
+
data["api_key"],
|
|
661
|
+
desc
|
|
662
|
+
)
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
|
|
542
667
|
# Gestion clés API (HARD dossier aait_store/keys)
|
|
543
668
|
# Enregistre un fichier JSON {service, api_key_encrypted, description}
|
|
544
669
|
def enregistrer_config_api_secure(service_name, api_key, description=""):
|
|
@@ -435,10 +435,8 @@ def check_new_emails(offusc_conf_agent,type_co, list_agent_email=[]):
|
|
|
435
435
|
|
|
436
436
|
elif type_co == "MICROSOFT_EXCHANGE_OAUTH2_MICROSOFT_GRAPH":
|
|
437
437
|
try:
|
|
438
|
-
print("🔍 [DEBUG] Début de la vérification des emails avec Microsoft Graph OAuth2")
|
|
439
438
|
client_id, client_secret, tenant_id, user_email = keys_manager.lire_config_oauth2(
|
|
440
|
-
offusc_conf_agent)
|
|
441
|
-
print(f"🔍 [DEBUG] Configuration lue - User: {user_email}, Tenant: {tenant_id}")
|
|
439
|
+
offusc_conf_agent, type=type_co)
|
|
442
440
|
|
|
443
441
|
authority = f"https://login.microsoftonline.com/{tenant_id}"
|
|
444
442
|
|
|
@@ -447,14 +445,12 @@ def check_new_emails(offusc_conf_agent,type_co, list_agent_email=[]):
|
|
|
447
445
|
client_credential=client_secret,
|
|
448
446
|
authority=authority
|
|
449
447
|
)
|
|
450
|
-
print("🔍 [DEBUG] Application MSAL créée")
|
|
451
448
|
|
|
452
449
|
# Essayer d'abord avec les permissions d'application (Client Credentials)
|
|
453
450
|
token_result = app.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"])
|
|
454
451
|
if "access_token" not in token_result:
|
|
455
452
|
raise Exception("Impossible d'obtenir un token : ", token_result.get("error_description"))
|
|
456
453
|
|
|
457
|
-
print("🔍 [DEBUG] Token d'accès obtenu avec succès (Client Credentials)")
|
|
458
454
|
access_token = token_result['access_token']
|
|
459
455
|
headers = {
|
|
460
456
|
'Authorization': f'Bearer {access_token}',
|
|
@@ -469,40 +465,13 @@ def check_new_emails(offusc_conf_agent,type_co, list_agent_email=[]):
|
|
|
469
465
|
'$select': 'id,subject,sender,toRecipients,ccRecipients,receivedDateTime,body,hasAttachments'
|
|
470
466
|
}
|
|
471
467
|
|
|
472
|
-
print(f"🔍 [DEBUG] Requête Graph API: {graph_url}")
|
|
473
|
-
print(f"🔍 [DEBUG] Paramètres: {params}")
|
|
474
468
|
|
|
475
469
|
try:
|
|
476
470
|
response = requests.get(graph_url, headers=headers, params=params)
|
|
477
471
|
response.raise_for_status()
|
|
478
472
|
emails_data = response.json()
|
|
479
|
-
print(
|
|
480
|
-
f"🔍 [DEBUG] Réponse Graph API reçue - Nombre d'emails non lus: {len(emails_data.get('value', []))}")
|
|
481
473
|
except requests.exceptions.HTTPError as e:
|
|
482
474
|
if response.status_code == 403:
|
|
483
|
-
print("🔍 [DEBUG] Erreur 403 - Permissions insuffisantes")
|
|
484
|
-
print("🔍 [DEBUG] ==============================================")
|
|
485
|
-
print("🔍 [DEBUG] ACTION REQUISE - Contactez votre IT Admin:")
|
|
486
|
-
print("🔍 [DEBUG] ==============================================")
|
|
487
|
-
print("🔍 [DEBUG] Votre application Azure AD manque des permissions.")
|
|
488
|
-
print("🔍 [DEBUG] App: IA-ODATAMINING")
|
|
489
|
-
print("🔍 [DEBUG] ID: 30ae55f5-f41e-4d44-afcc-082e4b803ba1")
|
|
490
|
-
print("🔍 [DEBUG] Tenant: 9988c2b8-3feb-4426-aeb7-b8d695bcd025")
|
|
491
|
-
print("🔍 [DEBUG] ")
|
|
492
|
-
print("🔍 [DEBUG] Permissions manquantes (Application type):")
|
|
493
|
-
print("🔍 [DEBUG] - Mail.Read - pour lire les emails")
|
|
494
|
-
print("🔍 [DEBUG] - Mail.Send - pour envoyer des emails")
|
|
495
|
-
print("🔍 [DEBUG] ")
|
|
496
|
-
print("🔍 [DEBUG] INFORMATIONS POUR VOTRE IT ADMIN:")
|
|
497
|
-
print("🔍 [DEBUG] 1. Azure Portal → Azure AD → App registrations")
|
|
498
|
-
print("🔍 [DEBUG] 2. Trouver l'app: IA-ODATAMINING")
|
|
499
|
-
print("🔍 [DEBUG] 3. API permissions → Add permission → Microsoft Graph")
|
|
500
|
-
print("🔍 [DEBUG] 4. Application permissions → Mail.Read + Mail.Send")
|
|
501
|
-
print("🔍 [DEBUG] 5. Grant admin consent")
|
|
502
|
-
print("🔍 [DEBUG] ")
|
|
503
|
-
print("🔍 [DEBUG] URL de consentement admin:")
|
|
504
|
-
print(f"🔍 [DEBUG] https://login.microsoftonline.com/{tenant_id}/adminconsent?client_id={client_id}")
|
|
505
|
-
print("🔍 [DEBUG] ==============================================")
|
|
506
475
|
raise Exception(
|
|
507
476
|
"❌ Permissions insuffisantes. Contactez votre IT Admin pour ajouter Mail.Read et Mail.Send permissions à l'application IA-ODATAMINING.")
|
|
508
477
|
else:
|
|
@@ -511,7 +480,6 @@ def check_new_emails(offusc_conf_agent,type_co, list_agent_email=[]):
|
|
|
511
480
|
print("Aucun nouveau mail.")
|
|
512
481
|
else:
|
|
513
482
|
for i, email_item in enumerate(emails_data['value']):
|
|
514
|
-
print(f"🔍 [DEBUG] Traitement de l'email {i + 1}/{len(emails_data['value'])}")
|
|
515
483
|
if list_agent_email:
|
|
516
484
|
white_list, black_list = keys_manager.lire_list_email(list_agent_email)
|
|
517
485
|
print(f"🔍 [DEBUG] Listes chargées - White: {len(white_list)}, Black: {len(black_list)}")
|
|
@@ -521,60 +489,48 @@ def check_new_emails(offusc_conf_agent,type_co, list_agent_email=[]):
|
|
|
521
489
|
time.sleep(1.5)
|
|
522
490
|
output_lines = []
|
|
523
491
|
|
|
524
|
-
email_id = email_item[
|
|
525
|
-
from_ = email_item['sender']['emailAddress']['address']
|
|
526
|
-
subject = email_item.get('subject', '(Sans sujet)')
|
|
527
|
-
to_emails = [rec['emailAddress']['address'] for rec in email_item.get('toRecipients', [])]
|
|
528
|
-
cc_emails = [rec['emailAddress']['address'] for rec in email_item.get('ccRecipients', [])]
|
|
492
|
+
email_id = email_item["id"]
|
|
529
493
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
494
|
+
from_ = (email_item.get("from") or {}).get("emailAddress", {}).get("address")
|
|
495
|
+
if not from_:
|
|
496
|
+
from_ = (email_item.get("sender") or {}).get("emailAddress", {}).get("address")
|
|
533
497
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
print(f"🔍 [DEBUG] Marquage comme lu: {mark_read_url}")
|
|
538
|
-
requests.patch(mark_read_url, headers=headers, json=patch_data)
|
|
498
|
+
subject = email_item.get("subject", "(Sans sujet)")
|
|
499
|
+
to_emails = [rec["emailAddress"]["address"] for rec in email_item.get("toRecipients", [])]
|
|
500
|
+
cc_emails = [rec["emailAddress"]["address"] for rec in email_item.get("ccRecipients", [])]
|
|
539
501
|
|
|
502
|
+
mark_read_url = f"https://graph.microsoft.com/v1.0/users/{user_email}/messages/{email_id}"
|
|
503
|
+
requests.patch(mark_read_url, headers=headers, json={"isRead": True})
|
|
540
504
|
# Récupérer le corps du message
|
|
541
505
|
body = ""
|
|
542
506
|
if email_item.get('body'):
|
|
543
507
|
body_content = email_item['body'].get('content', '')
|
|
544
508
|
if email_item['body'].get('contentType') == 'html':
|
|
545
|
-
print("🔍 [DEBUG] Corps HTML détecté, nettoyage en cours")
|
|
546
509
|
soup = BeautifulSoup(body_content, "html.parser")
|
|
547
510
|
for block in soup.find_all(["footer", "style", "script"]):
|
|
548
511
|
block.decompose()
|
|
549
512
|
body = soup.get_text(separator="\n", strip=True)
|
|
550
513
|
else:
|
|
551
514
|
body = body_content.strip()
|
|
552
|
-
print(f"🔍 [DEBUG] Corps du message extrait (longueur: {len(body)})")
|
|
553
515
|
|
|
554
516
|
folder = mail_in_folder(user_email, "in")
|
|
555
517
|
if folder is None:
|
|
556
518
|
print("Erreur dans le folder de mail")
|
|
557
519
|
continue
|
|
558
|
-
print(f"🔍 [DEBUG] Dossier de mail: {folder}")
|
|
559
520
|
|
|
560
521
|
ignored_pj = ""
|
|
561
522
|
# Traiter les pièces jointes si elles existent
|
|
562
523
|
if email_item.get('hasAttachments'):
|
|
563
|
-
print("🔍 [DEBUG] Pièces jointes détectées, récupération en cours")
|
|
564
524
|
attachments_url = f"https://graph.microsoft.com/v1.0/users/{user_email}/messages/{email_id}/attachments"
|
|
565
525
|
att_response = requests.get(attachments_url, headers=headers)
|
|
566
526
|
att_response.raise_for_status()
|
|
567
527
|
attachments_data = att_response.json()
|
|
568
|
-
|
|
569
|
-
print(f"🔍 [DEBUG] {len(attachments_data.get('value', []))} pièce(s) jointe(s) trouvée(s)")
|
|
570
528
|
for attachment in attachments_data.get('value', []):
|
|
571
529
|
attachment_name = attachment.get('name', '')
|
|
572
|
-
print(f"🔍 [DEBUG] Pièce jointe: {attachment_name}")
|
|
573
530
|
if len(attachment_name) < 5:
|
|
574
531
|
continue
|
|
575
532
|
if not (attachment_name.endswith(".pdf") or attachment_name.endswith(".docx")):
|
|
576
533
|
ignored_pj += (";" if ignored_pj else "") + attachment_name
|
|
577
|
-
print(f"🔍 [DEBUG] Pièce jointe ignorée: {attachment_name}")
|
|
578
534
|
continue
|
|
579
535
|
|
|
580
536
|
folder_pj = os.path.join(folder, "pj")
|
|
@@ -585,7 +541,6 @@ def check_new_emails(offusc_conf_agent,type_co, list_agent_email=[]):
|
|
|
585
541
|
content_bytes = base64.b64decode(attachment.get('contentBytes', ''))
|
|
586
542
|
with open(filepath, "wb") as f:
|
|
587
543
|
f.write(content_bytes)
|
|
588
|
-
print(f"🔍 [DEBUG] Pièce jointe sauvegardée: {filepath}")
|
|
589
544
|
|
|
590
545
|
# Format sortie
|
|
591
546
|
output_lines = [
|
|
@@ -613,14 +568,10 @@ def check_new_emails(offusc_conf_agent,type_co, list_agent_email=[]):
|
|
|
613
568
|
|
|
614
569
|
mail_txt_path = os.path.join(folder, "mail.txt")
|
|
615
570
|
mail_ok_path = os.path.join(folder, "mail.ok")
|
|
616
|
-
print(f"🔍 [DEBUG] Sauvegarde du mail: {mail_txt_path}")
|
|
617
571
|
with open(mail_txt_path, "w", encoding="utf-8") as f:
|
|
618
572
|
f.write("\n".join(output_lines))
|
|
619
573
|
with open(mail_ok_path, "w") as f:
|
|
620
574
|
pass
|
|
621
|
-
print("🔍 [DEBUG] Fichiers créés: mail.txt et mail.ok")
|
|
622
|
-
|
|
623
|
-
print("🔍 [DEBUG] Vérification des emails terminée")
|
|
624
575
|
|
|
625
576
|
except Exception as e:
|
|
626
577
|
print(f"Erreur Graph API lors du traitement du mail : {e}")
|
|
@@ -858,17 +809,14 @@ def check_send_new_emails(offusc_conf_agent,type_co):
|
|
|
858
809
|
print(f"❌ Erreur lors de l'envoi avec OAuth2 : {e}")
|
|
859
810
|
elif type_co == "MICROSOFT_EXCHANGE_OAUTH2_MICROSOFT_GRAPH":
|
|
860
811
|
try:
|
|
861
|
-
print("📤 [DEBUG] Début de la vérification des emails à envoyer avec Microsoft Graph OAuth2")
|
|
862
812
|
client_id, client_secret, tenant_id, user_email = keys_manager.lire_config_oauth2(
|
|
863
813
|
offusc_conf_agent)
|
|
864
|
-
print(f"📤 [DEBUG] Configuration lue - User: {user_email}, Tenant: {tenant_id}")
|
|
865
814
|
|
|
866
815
|
# Déduire l'alias pour le nom du dossier
|
|
867
816
|
agent = user_email
|
|
868
817
|
alias = user_email # tu peux adapter si tu veux un alias distinct plus tard
|
|
869
818
|
|
|
870
819
|
chemin_dossier_in, chemin_dossier_out = mail_in_folder(agent, "out")
|
|
871
|
-
print(f"📤 [DEBUG] Dossiers - In: {chemin_dossier_in}, Out: {chemin_dossier_out}")
|
|
872
820
|
|
|
873
821
|
authority = f"https://login.microsoftonline.com/{tenant_id}"
|
|
874
822
|
|
|
@@ -878,14 +826,12 @@ def check_send_new_emails(offusc_conf_agent,type_co):
|
|
|
878
826
|
client_credential=client_secret,
|
|
879
827
|
authority=authority
|
|
880
828
|
)
|
|
881
|
-
print("📤 [DEBUG] Application MSAL créée")
|
|
882
829
|
|
|
883
830
|
token_result = app.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"])
|
|
884
831
|
|
|
885
832
|
if "access_token" not in token_result:
|
|
886
833
|
raise Exception("Impossible d'obtenir un token : ", token_result.get("error_description"))
|
|
887
834
|
|
|
888
|
-
print("📤 [DEBUG] Token d'accès obtenu avec succès (Client Credentials)")
|
|
889
835
|
access_token = token_result['access_token']
|
|
890
836
|
headers = {
|
|
891
837
|
'Authorization': f'Bearer {access_token}',
|
|
@@ -893,26 +839,16 @@ def check_send_new_emails(offusc_conf_agent,type_co):
|
|
|
893
839
|
}
|
|
894
840
|
|
|
895
841
|
if os.path.exists(chemin_dossier_out) and os.path.isdir(chemin_dossier_out):
|
|
896
|
-
print("📤 [DEBUG] Dossier de sortie trouvé, lecture du contenu")
|
|
897
842
|
contenus = os.listdir(chemin_dossier_out)
|
|
898
|
-
print(f"📤 [DEBUG] Contenu du dossier: {contenus}")
|
|
899
843
|
if contenus:
|
|
900
844
|
for contenu in contenus:
|
|
901
845
|
mail_ok_path = os.path.join(chemin_dossier_out, contenu, "mail.ok")
|
|
902
|
-
print(f"📤 [DEBUG] Vérification du fichier mail.ok: {mail_ok_path}")
|
|
903
846
|
if os.path.exists(mail_ok_path):
|
|
904
847
|
chemin = os.path.join(chemin_dossier_out, contenu, "mail.txt")
|
|
905
|
-
print(f"📤 [DEBUG] Lecture du message depuis: {chemin}")
|
|
906
848
|
infos = lire_message(chemin)
|
|
907
|
-
print(f"📤 [DEBUG] Informations du message lues: {list(infos.keys())}")
|
|
908
849
|
|
|
909
850
|
cles_requises = ["eme", "des", "cop", "pri", "tit", "txt"]
|
|
910
851
|
if all(cle in infos for cle in cles_requises):
|
|
911
|
-
print("📤 [DEBUG] Toutes les clés requises sont présentes")
|
|
912
|
-
print(f"📤 [DEBUG] Envoi vers: {infos['eme']}")
|
|
913
|
-
print(f"📤 [DEBUG] Sujet: {infos['tit']}")
|
|
914
|
-
print(f"📤 [DEBUG] Contenu (longueur): {len(infos['txt'])}")
|
|
915
|
-
|
|
916
852
|
# Construire le message pour Microsoft Graph
|
|
917
853
|
message_data = {
|
|
918
854
|
"message": {
|
|
@@ -934,39 +870,19 @@ def check_send_new_emails(offusc_conf_agent,type_co):
|
|
|
934
870
|
|
|
935
871
|
# Envoyer l'email via Microsoft Graph
|
|
936
872
|
send_url = f"https://graph.microsoft.com/v1.0/users/{user_email}/sendMail"
|
|
937
|
-
print(f"📤 [DEBUG] Envoi via Graph API: {send_url}")
|
|
938
873
|
try:
|
|
939
874
|
response = requests.post(send_url, headers=headers, json=message_data)
|
|
940
875
|
response.raise_for_status()
|
|
941
|
-
print("📤 [DEBUG] Email envoyé avec succès")
|
|
942
876
|
except requests.exceptions.HTTPError as e:
|
|
943
877
|
if response.status_code == 403:
|
|
944
|
-
print("📤 [DEBUG] Erreur 403 - Permissions insuffisantes pour l'envoi")
|
|
945
|
-
print("📤 [DEBUG] ==============================================")
|
|
946
|
-
print("📤 [DEBUG] ACTION REQUISE - Contactez votre IT Admin:")
|
|
947
|
-
print("📤 [DEBUG] ==============================================")
|
|
948
|
-
print("📤 [DEBUG] Permission manquante: Mail.Send (Application)")
|
|
949
|
-
print("📤 [DEBUG] App: IA-ODATAMINING")
|
|
950
|
-
print("📤 [DEBUG] ID: 30ae55f5-f41e-4d44-afcc-082e4b803ba1")
|
|
951
|
-
print("📤 [DEBUG] Tenant: 9988c2b8-3feb-4426-aeb7-b8d695bcd025")
|
|
952
|
-
print("📤 [DEBUG] ")
|
|
953
|
-
print("📤 [DEBUG] INFORMATIONS POUR VOTRE IT ADMIN:")
|
|
954
|
-
print("📤 [DEBUG] 1. Azure Portal → Azure AD → App registrations")
|
|
955
|
-
print("📤 [DEBUG] 2. Trouver l'app: IA-ODATAMINING")
|
|
956
|
-
print("📤 [DEBUG] 3. API permissions → Add permission → Microsoft Graph")
|
|
957
|
-
print("📤 [DEBUG] 4. Application permissions → Mail.Send")
|
|
958
|
-
print("📤 [DEBUG] 5. Grant admin consent")
|
|
959
|
-
print("📤 [DEBUG] ==============================================")
|
|
960
878
|
raise Exception(
|
|
961
879
|
"❌ Permission Mail.Send manquante. Contactez votre IT Admin pour ajouter cette permission à l'application IA-ODATAMINING.")
|
|
962
880
|
else:
|
|
963
881
|
raise e
|
|
964
882
|
|
|
965
883
|
time.sleep(1)
|
|
966
|
-
print("📤 [DEBUG] Nettoyage des dossiers")
|
|
967
884
|
MetManagement.reset_folder(os.path.join(chemin_dossier_in, contenu), recreate=False)
|
|
968
885
|
MetManagement.reset_folder(os.path.join(chemin_dossier_out, contenu), recreate=False)
|
|
969
|
-
print("📤 [DEBUG] Dossiers nettoyés")
|
|
970
886
|
else:
|
|
971
887
|
print("\n\n Il manque des clefs dans le contenu du mail")
|
|
972
888
|
print(
|
|
@@ -1005,7 +921,7 @@ def list_conf_files(type_co):
|
|
|
1005
921
|
|
|
1006
922
|
|
|
1007
923
|
if __name__ == "__main__":
|
|
1008
|
-
type_co="
|
|
924
|
+
type_co="MICROSOFT_EXCHANGE_OAUTH2_MICROSOFT_GRAPH"
|
|
1009
925
|
list_agent_email = []
|
|
1010
926
|
offusc_conf_agents = list_conf_files(type_co)
|
|
1011
927
|
while True:
|
|
@@ -183,18 +183,21 @@ class OWExportMarkdown(widget.OWWidget):
|
|
|
183
183
|
)
|
|
184
184
|
else:
|
|
185
185
|
raise Exception("Word non détecté")
|
|
186
|
-
|
|
187
|
-
except Exception:
|
|
186
|
+
# PDF (docx -> pdf) avec chemin de sortie exact
|
|
188
187
|
try:
|
|
189
|
-
|
|
188
|
+
convert(docx_out, pdf_out)
|
|
190
189
|
except Exception:
|
|
191
|
-
|
|
192
|
-
|
|
190
|
+
# fallback pandoc->pdf (si LaTeX dispo)
|
|
191
|
+
try:
|
|
192
|
+
pypandoc.convert_file(tmp_md, to="pdf", outputfile=pdf_out)
|
|
193
|
+
except Exception:
|
|
194
|
+
self.error(f"Échec conversion PDF pour la ligne {i + 1}.")
|
|
195
|
+
pdf_out = ""
|
|
193
196
|
finally:
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
197
|
+
try:
|
|
198
|
+
os.remove(tmp_md)
|
|
199
|
+
except Exception:
|
|
200
|
+
pass
|
|
198
201
|
|
|
199
202
|
pdf_paths.append(pdf_out if os.path.isfile(pdf_out) else "")
|
|
200
203
|
docx_paths.append(docx_out if os.path.isfile(docx_out) else "")
|