io4it 2.1.7__tar.gz → 2.1.7.2__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.
Files changed (81) hide show
  1. {io4it-2.1.7 → io4it-2.1.7.2}/PKG-INFO +1 -1
  2. {io4it-2.1.7 → io4it-2.1.7.2}/io4it.egg-info/PKG-INFO +1 -1
  3. {io4it-2.1.7 → io4it-2.1.7.2}/io4it.egg-info/SOURCES.txt +5 -4
  4. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/utils/mail.py +326 -3
  5. io4it-2.1.7.2/orangecontrib/IO4IT/utils/secret_manager.py +300 -0
  6. io4it-2.1.7/orangecontrib/IO4IT/widgets/OWDoclingMarkdownizerSimple.py → io4it-2.1.7.2/orangecontrib/IO4IT/widgets/OWDoclingToMarkdown.py +3 -3
  7. io4it-2.1.7/orangecontrib/IO4IT/widgets/OWExtractTablesDocxToCSV.py → io4it-2.1.7.2/orangecontrib/IO4IT/widgets/OWExtractTablesDocxToXlsx.py +121 -30
  8. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/OWInboxMailMonitoring.py +2 -1
  9. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/OWS3Uploader.py +3 -3
  10. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/OWmailLoader.py +2 -0
  11. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/OWmailSender.py +2 -2
  12. io4it-2.1.7/orangecontrib/IO4IT/widgets/designer/owdocxtocsv.ui → io4it-2.1.7.2/orangecontrib/IO4IT/widgets/designer/owdocxtoxlsx.ui +37 -9
  13. {io4it-2.1.7 → io4it-2.1.7.2}/setup.py +1 -1
  14. {io4it-2.1.7 → io4it-2.1.7.2}/io4it.egg-info/dependency_links.txt +0 -0
  15. {io4it-2.1.7 → io4it-2.1.7.2}/io4it.egg-info/entry_points.txt +0 -0
  16. {io4it-2.1.7 → io4it-2.1.7.2}/io4it.egg-info/namespace_packages.txt +0 -0
  17. {io4it-2.1.7 → io4it-2.1.7.2}/io4it.egg-info/requires.txt +0 -0
  18. {io4it-2.1.7 → io4it-2.1.7.2}/io4it.egg-info/top_level.txt +0 -0
  19. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/__init__.py +0 -0
  20. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/ocr_function/__init__.py +0 -0
  21. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/ocr_function/word_converter.py +0 -0
  22. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/utils/__init__.py +0 -0
  23. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/utils/offuscation_basique.py +0 -0
  24. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/utils/pool_exec_utils.py +0 -0
  25. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/utils/utils_md.py +0 -0
  26. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/OWChatGpt.py +0 -0
  27. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/OWDeep_Search.py +0 -0
  28. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/OWExportMarkdown.py +0 -0
  29. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/OWMarkdownLoader.py +0 -0
  30. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/OWMarkdownizer.py +0 -0
  31. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/OWOfficeNormalizer.py +0 -0
  32. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/OWPdfType.py +0 -0
  33. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/OWProcessPoolExecutor.py +0 -0
  34. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/OWS3downloader.py +0 -0
  35. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/OWS3list.py +0 -0
  36. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/OWSpeechToText.py +0 -0
  37. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/OWwordpdf2docx.py +0 -0
  38. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/__init__.py +0 -0
  39. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/designer/__init__.py +0 -0
  40. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/designer/nogui.ui +0 -0
  41. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/designer/ow_file_ext_selector.ui +0 -0
  42. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/designer/owchatgpt.ui +0 -0
  43. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/designer/owdeepsearch.ui +0 -0
  44. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/designer/owdoclingasr.ui +0 -0
  45. /io4it-2.1.7/orangecontrib/IO4IT/widgets/designer/owdoclingmarkdownizersimple.ui → /io4it-2.1.7.2/orangecontrib/IO4IT/widgets/designer/owdoclingtomarkdown.ui +0 -0
  46. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/designer/owexportmarkdown.ui +0 -0
  47. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/designer/owinboxmailmonitoring.ui +0 -0
  48. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/designer/owmailloader.ui +0 -0
  49. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/designer/owmailsender.ui +0 -0
  50. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/designer/owmarkdownizer.ui +0 -0
  51. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/designer/owmarkdownloader.ui +0 -0
  52. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/designer/owofficenormalizer.ui +0 -0
  53. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/designer/owpdftype.ui +0 -0
  54. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/designer/owprocesspoolexecutor.ui +0 -0
  55. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/designer/owspeechtotext.ui +0 -0
  56. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/designer/owvisualizationer.ui +0 -0
  57. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/designer/wordpdf2docx.ui +0 -0
  58. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/__init__.py +0 -0
  59. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/chatgpt.png +0 -0
  60. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/check_pdf.png +0 -0
  61. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/deepsearch.svg +0 -0
  62. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/dep_md_old.png +0 -0
  63. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/download.png +0 -0
  64. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/export_md.png +0 -0
  65. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/extract_table.png +0 -0
  66. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/file_extensor.png +0 -0
  67. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/list_aws.png +0 -0
  68. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/load_md.png +0 -0
  69. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/mail_loader.png +0 -0
  70. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/mail_writer.png +0 -0
  71. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/md.png +0 -0
  72. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/monitor-email.svg +0 -0
  73. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/office_normalizer.png +0 -0
  74. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/process_pool_executor.png +0 -0
  75. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/speech_to_text.png +0 -0
  76. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/upload.png +0 -0
  77. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/visualizationer.png +0 -0
  78. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons/wordpdf2docx.png +0 -0
  79. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/IO4IT/widgets/icons_dev/__init__.py +0 -0
  80. {io4it-2.1.7 → io4it-2.1.7.2}/orangecontrib/__init__.py +0 -0
  81. {io4it-2.1.7 → io4it-2.1.7.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: io4it
3
- Version: 2.1.7
3
+ Version: 2.1.7.2
4
4
  Home-page:
5
5
  Author:
6
6
  Author-email:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: io4it
3
- Version: 2.1.7
3
+ Version: 2.1.7.2
4
4
  Home-page:
5
5
  Author:
6
6
  Author-email:
@@ -14,12 +14,13 @@ orangecontrib/IO4IT/utils/__init__.py
14
14
  orangecontrib/IO4IT/utils/mail.py
15
15
  orangecontrib/IO4IT/utils/offuscation_basique.py
16
16
  orangecontrib/IO4IT/utils/pool_exec_utils.py
17
+ orangecontrib/IO4IT/utils/secret_manager.py
17
18
  orangecontrib/IO4IT/utils/utils_md.py
18
19
  orangecontrib/IO4IT/widgets/OWChatGpt.py
19
20
  orangecontrib/IO4IT/widgets/OWDeep_Search.py
20
- orangecontrib/IO4IT/widgets/OWDoclingMarkdownizerSimple.py
21
+ orangecontrib/IO4IT/widgets/OWDoclingToMarkdown.py
21
22
  orangecontrib/IO4IT/widgets/OWExportMarkdown.py
22
- orangecontrib/IO4IT/widgets/OWExtractTablesDocxToCSV.py
23
+ orangecontrib/IO4IT/widgets/OWExtractTablesDocxToXlsx.py
23
24
  orangecontrib/IO4IT/widgets/OWInboxMailMonitoring.py
24
25
  orangecontrib/IO4IT/widgets/OWMarkdownLoader.py
25
26
  orangecontrib/IO4IT/widgets/OWMarkdownizer.py
@@ -40,8 +41,8 @@ orangecontrib/IO4IT/widgets/designer/ow_file_ext_selector.ui
40
41
  orangecontrib/IO4IT/widgets/designer/owchatgpt.ui
41
42
  orangecontrib/IO4IT/widgets/designer/owdeepsearch.ui
42
43
  orangecontrib/IO4IT/widgets/designer/owdoclingasr.ui
43
- orangecontrib/IO4IT/widgets/designer/owdoclingmarkdownizersimple.ui
44
- orangecontrib/IO4IT/widgets/designer/owdocxtocsv.ui
44
+ orangecontrib/IO4IT/widgets/designer/owdoclingtomarkdown.ui
45
+ orangecontrib/IO4IT/widgets/designer/owdocxtoxlsx.ui
45
46
  orangecontrib/IO4IT/widgets/designer/owexportmarkdown.ui
46
47
  orangecontrib/IO4IT/widgets/designer/owinboxmailmonitoring.ui
47
48
  orangecontrib/IO4IT/widgets/designer/owmailloader.ui
@@ -11,8 +11,8 @@ import mimetypes
11
11
  from exchangelib import Credentials, HTMLBody, Message, Mailbox
12
12
  #from exchangelib.protocol import BaseProtocol, NoVerifyHTTPAdapter
13
13
  from exchangelib import OAuth2Credentials, Identity, Configuration, Account, DELEGATE
14
-
15
-
14
+ import requests
15
+ import base64
16
16
  from bs4 import BeautifulSoup
17
17
 
18
18
 
@@ -431,10 +431,202 @@ def check_new_emails(offusc_conf_agent,type_co, list_agent_email=[]):
431
431
  f.write("\n".join(output_lines))
432
432
  with open(os.path.join(folder, "mail.ok"), "w") as f:
433
433
  pass
434
+ except Exception as e:
435
+ print(f"Erreur OAuth2 lors du traitement du mail : {e}")
436
+
437
+ elif type_co == "MICROSOFT_EXCHANGE_OAUTH2_MICROSOFT_GRAPH":
438
+ try:
439
+ print("🔍 [DEBUG] Début de la vérification des emails avec Microsoft Graph OAuth2")
440
+ client_id, client_secret, tenant_id, user_email = offuscation_basique.lire_config_cli_oauth2(
441
+ offusc_conf_agent)
442
+ print(f"🔍 [DEBUG] Configuration lue - User: {user_email}, Tenant: {tenant_id}")
443
+
444
+ authority = f"https://login.microsoftonline.com/{tenant_id}"
445
+
446
+ app = ConfidentialClientApplication(
447
+ client_id=client_id,
448
+ client_credential=client_secret,
449
+ authority=authority
450
+ )
451
+ print("🔍 [DEBUG] Application MSAL créée")
452
+
453
+ # Essayer d'abord avec les permissions d'application (Client Credentials)
454
+ token_result = app.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"])
455
+ if "access_token" not in token_result:
456
+ raise Exception("Impossible d'obtenir un token : ", token_result.get("error_description"))
457
+
458
+ print("🔍 [DEBUG] Token d'accès obtenu avec succès (Client Credentials)")
459
+ access_token = token_result['access_token']
460
+ headers = {
461
+ 'Authorization': f'Bearer {access_token}',
462
+ 'Content-Type': 'application/json'
463
+ }
464
+
465
+ # Récupérer les emails non lus
466
+ graph_url = f"https://graph.microsoft.com/v1.0/users/{user_email}/messages"
467
+ params = {
468
+ '$filter': 'isRead eq false',
469
+ '$orderby': 'receivedDateTime asc',
470
+ '$select': 'id,subject,sender,toRecipients,ccRecipients,receivedDateTime,body,hasAttachments'
471
+ }
472
+
473
+ print(f"🔍 [DEBUG] Requête Graph API: {graph_url}")
474
+ print(f"🔍 [DEBUG] Paramètres: {params}")
475
+
476
+ try:
477
+ response = requests.get(graph_url, headers=headers, params=params)
478
+ response.raise_for_status()
479
+ emails_data = response.json()
480
+ print(
481
+ f"🔍 [DEBUG] Réponse Graph API reçue - Nombre d'emails non lus: {len(emails_data.get('value', []))}")
482
+ except requests.exceptions.HTTPError as e:
483
+ if response.status_code == 403:
484
+ print("🔍 [DEBUG] Erreur 403 - Permissions insuffisantes")
485
+ print("🔍 [DEBUG] ==============================================")
486
+ print("🔍 [DEBUG] ACTION REQUISE - Contactez votre IT Admin:")
487
+ print("🔍 [DEBUG] ==============================================")
488
+ print("🔍 [DEBUG] Votre application Azure AD manque des permissions.")
489
+ print("🔍 [DEBUG] App: IA-ODATAMINING")
490
+ print("🔍 [DEBUG] ID: 30ae55f5-f41e-4d44-afcc-082e4b803ba1")
491
+ print("🔍 [DEBUG] Tenant: 9988c2b8-3feb-4426-aeb7-b8d695bcd025")
492
+ print("🔍 [DEBUG] ")
493
+ print("🔍 [DEBUG] Permissions manquantes (Application type):")
494
+ print("🔍 [DEBUG] - Mail.Read - pour lire les emails")
495
+ print("🔍 [DEBUG] - Mail.Send - pour envoyer des emails")
496
+ print("🔍 [DEBUG] ")
497
+ print("🔍 [DEBUG] INFORMATIONS POUR VOTRE IT ADMIN:")
498
+ print("🔍 [DEBUG] 1. Azure Portal → Azure AD → App registrations")
499
+ print("🔍 [DEBUG] 2. Trouver l'app: IA-ODATAMINING")
500
+ print("🔍 [DEBUG] 3. API permissions → Add permission → Microsoft Graph")
501
+ print("🔍 [DEBUG] 4. Application permissions → Mail.Read + Mail.Send")
502
+ print("🔍 [DEBUG] 5. Grant admin consent")
503
+ print("🔍 [DEBUG] ")
504
+ print("🔍 [DEBUG] URL de consentement admin:")
505
+ print(f"🔍 [DEBUG] https://login.microsoftonline.com/{tenant_id}/adminconsent?client_id={client_id}")
506
+ print("🔍 [DEBUG] ==============================================")
507
+ raise Exception(
508
+ "❌ Permissions insuffisantes. Contactez votre IT Admin pour ajouter Mail.Read et Mail.Send permissions à l'application IA-ODATAMINING.")
509
+ else:
510
+ raise e
511
+ if not emails_data.get('value'):
512
+ print("Aucun nouveau mail.")
513
+ else:
514
+ for i, email_item in enumerate(emails_data['value']):
515
+ print(f"🔍 [DEBUG] Traitement de l'email {i + 1}/{len(emails_data['value'])}")
516
+ if list_agent_email:
517
+ white_list, black_list = offuscation_basique.lire_list_email(list_agent_email)
518
+ print(f"🔍 [DEBUG] Listes chargées - White: {len(white_list)}, Black: {len(black_list)}")
519
+ else:
520
+ white_list, black_list = [], []
521
+
522
+ time.sleep(1.5)
523
+ output_lines = []
524
+
525
+ email_id = email_item['id']
526
+ from_ = email_item['sender']['emailAddress']['address']
527
+ subject = email_item.get('subject', '(Sans sujet)')
528
+ to_emails = [rec['emailAddress']['address'] for rec in email_item.get('toRecipients', [])]
529
+ cc_emails = [rec['emailAddress']['address'] for rec in email_item.get('ccRecipients', [])]
530
+
531
+ print(f"🔍 [DEBUG] Email ID: {email_id}")
532
+ print(f"🔍 [DEBUG] De: {from_}, Sujet: {subject}")
533
+ print(f"🔍 [DEBUG] Destinataires: {to_emails}, CC: {cc_emails}")
534
+
535
+ # Marquer comme lu
536
+ mark_read_url = f"https://graph.microsoft.com/v1.0/users/{user_email}/messages/{email_id}"
537
+ patch_data = {'isRead': True}
538
+ print(f"🔍 [DEBUG] Marquage comme lu: {mark_read_url}")
539
+ requests.patch(mark_read_url, headers=headers, json=patch_data)
540
+
541
+ # Récupérer le corps du message
542
+ body = ""
543
+ if email_item.get('body'):
544
+ body_content = email_item['body'].get('content', '')
545
+ if email_item['body'].get('contentType') == 'html':
546
+ print("🔍 [DEBUG] Corps HTML détecté, nettoyage en cours")
547
+ soup = BeautifulSoup(body_content, "html.parser")
548
+ for block in soup.find_all(["footer", "style", "script"]):
549
+ block.decompose()
550
+ body = soup.get_text(separator="\n", strip=True)
551
+ else:
552
+ body = body_content.strip()
553
+ print(f"🔍 [DEBUG] Corps du message extrait (longueur: {len(body)})")
554
+
555
+ folder = mail_in_folder(user_email, "in")
556
+ if folder is None:
557
+ print("Erreur dans le folder de mail")
558
+ continue
559
+ print(f"🔍 [DEBUG] Dossier de mail: {folder}")
560
+
561
+ ignored_pj = ""
562
+ # Traiter les pièces jointes si elles existent
563
+ if email_item.get('hasAttachments'):
564
+ print("🔍 [DEBUG] Pièces jointes détectées, récupération en cours")
565
+ attachments_url = f"https://graph.microsoft.com/v1.0/users/{user_email}/messages/{email_id}/attachments"
566
+ att_response = requests.get(attachments_url, headers=headers)
567
+ att_response.raise_for_status()
568
+ attachments_data = att_response.json()
569
+
570
+ print(f"🔍 [DEBUG] {len(attachments_data.get('value', []))} pièce(s) jointe(s) trouvée(s)")
571
+ for attachment in attachments_data.get('value', []):
572
+ attachment_name = attachment.get('name', '')
573
+ print(f"🔍 [DEBUG] Pièce jointe: {attachment_name}")
574
+ if len(attachment_name) < 5:
575
+ continue
576
+ if not (attachment_name.endswith(".pdf") or attachment_name.endswith(".docx")):
577
+ ignored_pj += (";" if ignored_pj else "") + attachment_name
578
+ print(f"🔍 [DEBUG] Pièce jointe ignorée: {attachment_name}")
579
+ continue
580
+
581
+ folder_pj = os.path.join(folder, "pj")
582
+ os.makedirs(folder_pj, exist_ok=True)
583
+ filepath = os.path.join(folder_pj, attachment_name)
584
+
585
+ # Décoder le contenu base64
586
+ content_bytes = base64.b64decode(attachment.get('contentBytes', ''))
587
+ with open(filepath, "wb") as f:
588
+ f.write(content_bytes)
589
+ print(f"🔍 [DEBUG] Pièce jointe sauvegardée: {filepath}")
590
+
591
+ # Format sortie
592
+ output_lines = [
593
+ f"#$who : {user_email}",
594
+ f"#$eme : {from_}",
595
+ f"#$des : {', '.join(to_emails)}",
596
+ f"#$cop : {', '.join(cc_emails)}",
597
+ "#$pri : Normale",
598
+ f"#$tit : {subject}",
599
+ f"#$ipj : {ignored_pj}",
600
+ f"#$txt : {body.strip()}",
601
+ ""
602
+ ]
603
+
604
+ print("----------------------------------------")
605
+ print(f"Mail reçu de {from_}")
606
+ print("----------------------------------------")
607
+
608
+ if white_list and from_ not in white_list:
609
+ print("Cette adresse n'est pas dans la white list")
610
+ continue
611
+ if black_list and from_ in black_list:
612
+ print("Cette adresse est dans la black list")
613
+ continue
614
+
615
+ mail_txt_path = os.path.join(folder, "mail.txt")
616
+ mail_ok_path = os.path.join(folder, "mail.ok")
617
+ print(f"🔍 [DEBUG] Sauvegarde du mail: {mail_txt_path}")
618
+ with open(mail_txt_path, "w", encoding="utf-8") as f:
619
+ f.write("\n".join(output_lines))
620
+ with open(mail_ok_path, "w") as f:
621
+ pass
622
+ print("🔍 [DEBUG] Fichiers créés: mail.txt et mail.ok")
434
623
 
624
+ print("🔍 [DEBUG] Vérification des emails terminée")
435
625
 
436
626
  except Exception as e:
437
- print(f"Erreur OAuth2 lors du traitement du mail : {e}")
627
+ print(f"Erreur Graph API lors du traitement du mail : {e}")
628
+ print(f"🔍 [DEBUG] Erreur détaillée: {type(e).__name__}: {str(e)}")
629
+
438
630
 
439
631
  else:
440
632
  print("type de co non géré : attendu IMAP4_SSL, MICROSOFT_EXCHANGE_OWA ou MICROSOFT_EXCHANGE_OAUTH2")
@@ -665,6 +857,137 @@ def check_send_new_emails(offusc_conf_agent,type_co):
665
857
  print("Le dossier n'existe pas ou le chemin n'est pas un dossier.")
666
858
  except Exception as e:
667
859
  print(f"❌ Erreur lors de l'envoi avec OAuth2 : {e}")
860
+ elif type_co == "MICROSOFT_EXCHANGE_OAUTH2_MICROSOFT_GRAPH":
861
+ try:
862
+ print("📤 [DEBUG] Début de la vérification des emails à envoyer avec Microsoft Graph OAuth2")
863
+ client_id, client_secret, tenant_id, user_email = offuscation_basique.lire_config_cli_oauth2(
864
+ offusc_conf_agent)
865
+ print(f"📤 [DEBUG] Configuration lue - User: {user_email}, Tenant: {tenant_id}")
866
+
867
+ # Déduire l'alias pour le nom du dossier
868
+ agent = user_email
869
+ alias = user_email # tu peux adapter si tu veux un alias distinct plus tard
870
+
871
+ chemin_dossier_in, chemin_dossier_out = mail_in_folder(agent, "out")
872
+ print(f"📤 [DEBUG] Dossiers - In: {chemin_dossier_in}, Out: {chemin_dossier_out}")
873
+
874
+ authority = f"https://login.microsoftonline.com/{tenant_id}"
875
+
876
+ # === Authentification avec MSAL ===
877
+ app = ConfidentialClientApplication(
878
+ client_id=client_id,
879
+ client_credential=client_secret,
880
+ authority=authority
881
+ )
882
+ print("📤 [DEBUG] Application MSAL créée")
883
+
884
+ token_result = app.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"])
885
+
886
+ if "access_token" not in token_result:
887
+ raise Exception("Impossible d'obtenir un token : ", token_result.get("error_description"))
888
+
889
+ print("📤 [DEBUG] Token d'accès obtenu avec succès (Client Credentials)")
890
+ access_token = token_result['access_token']
891
+ headers = {
892
+ 'Authorization': f'Bearer {access_token}',
893
+ 'Content-Type': 'application/json'
894
+ }
895
+
896
+ if os.path.exists(chemin_dossier_out) and os.path.isdir(chemin_dossier_out):
897
+ print("📤 [DEBUG] Dossier de sortie trouvé, lecture du contenu")
898
+ contenus = os.listdir(chemin_dossier_out)
899
+ print(f"📤 [DEBUG] Contenu du dossier: {contenus}")
900
+ if contenus:
901
+ for contenu in contenus:
902
+ mail_ok_path = os.path.join(chemin_dossier_out, contenu, "mail.ok")
903
+ print(f"📤 [DEBUG] Vérification du fichier mail.ok: {mail_ok_path}")
904
+ if os.path.exists(mail_ok_path):
905
+ chemin = os.path.join(chemin_dossier_out, contenu, "mail.txt")
906
+ print(f"📤 [DEBUG] Lecture du message depuis: {chemin}")
907
+ infos = lire_message(chemin)
908
+ print(f"📤 [DEBUG] Informations du message lues: {list(infos.keys())}")
909
+
910
+ cles_requises = ["eme", "des", "cop", "pri", "tit", "txt"]
911
+ if all(cle in infos for cle in cles_requises):
912
+ print("📤 [DEBUG] Toutes les clés requises sont présentes")
913
+ print(f"📤 [DEBUG] Envoi vers: {infos['eme']}")
914
+ print(f"📤 [DEBUG] Sujet: {infos['tit']}")
915
+ print(f"📤 [DEBUG] Contenu (longueur): {len(infos['txt'])}")
916
+
917
+ # Construire le message pour Microsoft Graph
918
+ message_data = {
919
+ "message": {
920
+ "subject": infos["tit"],
921
+ "body": {
922
+ "contentType": "HTML",
923
+ "content": infos["txt"]
924
+ },
925
+ "toRecipients": [
926
+ {
927
+ "emailAddress": {
928
+ "address": infos["eme"]
929
+ }
930
+ }
931
+ ]
932
+ },
933
+ "saveToSentItems": True
934
+ }
935
+
936
+ # Envoyer l'email via Microsoft Graph
937
+ send_url = f"https://graph.microsoft.com/v1.0/users/{user_email}/sendMail"
938
+ print(f"📤 [DEBUG] Envoi via Graph API: {send_url}")
939
+ try:
940
+ response = requests.post(send_url, headers=headers, json=message_data)
941
+ response.raise_for_status()
942
+ print("📤 [DEBUG] Email envoyé avec succès")
943
+ except requests.exceptions.HTTPError as e:
944
+ if response.status_code == 403:
945
+ print("📤 [DEBUG] Erreur 403 - Permissions insuffisantes pour l'envoi")
946
+ print("📤 [DEBUG] ==============================================")
947
+ print("📤 [DEBUG] ACTION REQUISE - Contactez votre IT Admin:")
948
+ print("📤 [DEBUG] ==============================================")
949
+ print("📤 [DEBUG] Permission manquante: Mail.Send (Application)")
950
+ print("📤 [DEBUG] App: IA-ODATAMINING")
951
+ print("📤 [DEBUG] ID: 30ae55f5-f41e-4d44-afcc-082e4b803ba1")
952
+ print("📤 [DEBUG] Tenant: 9988c2b8-3feb-4426-aeb7-b8d695bcd025")
953
+ print("📤 [DEBUG] ")
954
+ print("📤 [DEBUG] INFORMATIONS POUR VOTRE IT ADMIN:")
955
+ print("📤 [DEBUG] 1. Azure Portal → Azure AD → App registrations")
956
+ print("📤 [DEBUG] 2. Trouver l'app: IA-ODATAMINING")
957
+ print("📤 [DEBUG] 3. API permissions → Add permission → Microsoft Graph")
958
+ print("📤 [DEBUG] 4. Application permissions → Mail.Send")
959
+ print("📤 [DEBUG] 5. Grant admin consent")
960
+ print("📤 [DEBUG] ==============================================")
961
+ raise Exception(
962
+ "❌ Permission Mail.Send manquante. Contactez votre IT Admin pour ajouter cette permission à l'application IA-ODATAMINING.")
963
+ else:
964
+ raise e
965
+
966
+ time.sleep(1)
967
+ print("📤 [DEBUG] Nettoyage des dossiers")
968
+ MetManagement.reset_folder(os.path.join(chemin_dossier_in, contenu), recreate=False)
969
+ MetManagement.reset_folder(os.path.join(chemin_dossier_out, contenu), recreate=False)
970
+ print("📤 [DEBUG] Dossiers nettoyés")
971
+ else:
972
+ print("\n\n Il manque des clefs dans le contenu du mail")
973
+ print(
974
+ f"📤 [DEBUG] Clés manquantes: {[cle for cle in cles_requises if cle not in infos]}")
975
+ else:
976
+ print(
977
+ f"\n\n KO § os.path.exists(os.path.join(chemin_dossier_out, contenu): {os.path.exists(os.path.join(chemin_dossier_out, contenu, 'mail.ok'))}")
978
+ else:
979
+ print("Le dossier est vide.")
980
+ else:
981
+ print("Le dossier n'existe pas ou le chemin n'est pas un dossier.")
982
+ print(f"📤 [DEBUG] Chemin vérifié: {chemin_dossier_out}")
983
+ print(
984
+ f"📤 [DEBUG] Existe: {os.path.exists(chemin_dossier_out)}, Est dossier: {os.path.isdir(chemin_dossier_out) if os.path.exists(chemin_dossier_out) else 'N/A'}")
985
+
986
+ print("📤 [DEBUG] Vérification des emails à envoyer terminée")
987
+
988
+ except Exception as e:
989
+ print(f"❌ Erreur lors de l'envoi avec Graph API : {e}")
990
+ print(f"📤 [DEBUG] Erreur détaillée: {type(e).__name__}: {str(e)}")
668
991
  else:
669
992
  print("type de co non valide")
670
993