Office365-REST-Python-Client 3.1.0__py3-none-any.whl → 3.3.0__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.
Files changed (3117) hide show
  1. office365/admin/admin.py +45 -0
  2. office365/admin/baseline_parameter.py +3 -0
  3. office365/admin/baseline_parameter_type.py +14 -0
  4. office365/admin/browser_shared_cookie.py +99 -0
  5. office365/admin/browser_site.py +101 -0
  6. office365/admin/browser_site_list.py +87 -0
  7. office365/admin/configuration_management.py +86 -0
  8. office365/admin/edge/edge.py +25 -0
  9. office365/admin/exchange/admin.py +35 -0
  10. office365/admin/exchange/exchange_message_trace.py +15 -1
  11. office365/admin/exchange/exchange_message_trace_status.py +2 -0
  12. office365/admin/internet_explorer_mode.py +28 -0
  13. office365/admin/message_tracing_root.py +28 -0
  14. office365/admin/microsoft365/apps.py +26 -0
  15. office365/admin/microsoft365/m365_apps_installation_options.py +47 -0
  16. office365/admin/people/insights_settings.py +21 -0
  17. office365/admin/people/profile_property_setting.py +27 -0
  18. office365/admin/people/profile_source.py +48 -0
  19. office365/admin/people/pronouns_settings.py +16 -0
  20. office365/admin/people/settings.py +58 -0
  21. office365/admin/report_settings.py +13 -0
  22. office365/admin/sharepoint/settings.py +88 -1
  23. office365/backuprestore/browse_session_base.py +101 -0
  24. office365/backuprestore/email_notifications_setting.py +40 -0
  25. office365/backuprestore/onedrive_for_business_browse_session.py +16 -0
  26. office365/backuprestore/onedrive_for_business_restore_session.py +68 -0
  27. office365/backuprestore/protection_unit_base.py +92 -0
  28. office365/backuprestore/restorepoints/collection.py +61 -0
  29. office365/backuprestore/restorepoints/search_result.py +6 -0
  30. office365/backuprestore/root.py +354 -0
  31. office365/backuprestore/serviceapps/service_app.py +74 -0
  32. office365/backuprestore/sharepoint_browse_session.py +16 -0
  33. office365/backuprestore/sharepoint_protection_policy.py +60 -0
  34. office365/backuprestore/sharepoint_restore_session.py +66 -0
  35. office365/booking/appointment.py +197 -0
  36. office365/booking/business/business.py +75 -1
  37. office365/booking/business/collection.py +22 -0
  38. office365/booking/currency.py +13 -0
  39. office365/booking/custom_question.py +40 -0
  40. office365/booking/customer.py +51 -0
  41. office365/booking/service.py +145 -1
  42. office365/booking/staff/member.py +76 -0
  43. office365/common/add_large_gallery_view_operation.py +8 -0
  44. office365/common/agent_identity.py +45 -0
  45. office365/common/agent_identity_blueprint.py +41 -0
  46. office365/common/agent_identity_blueprint_principal.py +34 -0
  47. office365/common/agent_user.py +7 -0
  48. office365/common/ai_interaction.py +108 -0
  49. office365/common/akamai_web_application_firewall_provider.py +31 -0
  50. office365/common/anonymous_calendar_sharing_free_busy_detail.py +7 -0
  51. office365/common/anonymous_calendar_sharing_free_busy_reviewer.py +7 -0
  52. office365/common/anonymous_calendar_sharing_free_busy_simple.py +7 -0
  53. office365/common/anonymous_guest_conversation_member.py +16 -0
  54. office365/common/apple_device_features_configuration_base.py +7 -0
  55. office365/common/apple_managed_identity_provider.py +31 -0
  56. office365/common/arkose_fraud_protection_provider.py +31 -0
  57. office365/common/attribute_set.py +21 -0
  58. office365/common/azure_communication_services_user_conversation_member.py +16 -0
  59. office365/common/b2_b_registration_metrics_base.py +27 -0
  60. office365/common/b2_b_sign_in_activity_metrics_base.py +37 -0
  61. office365/common/base_map_feature.py +7 -0
  62. office365/common/building.py +39 -0
  63. office365/common/building_map.py +41 -0
  64. office365/common/complex_extension_value.py +10 -0
  65. office365/common/configuration_baseline.py +40 -0
  66. office365/common/configuration_drift.py +68 -0
  67. office365/common/configuration_monitor.py +103 -0
  68. office365/common/configuration_monitoring_result.py +56 -0
  69. office365/common/configuration_snapshot_job.py +71 -0
  70. office365/common/contract.py +32 -0
  71. office365/common/cross_tenant_access_policy_configuration_default.py +163 -0
  72. office365/common/cross_tenant_access_policy_configuration_partner.py +188 -0
  73. office365/common/cross_tenant_calendar_availability_basic.py +7 -0
  74. office365/common/cross_tenant_calendar_availability_limited_details.py +7 -0
  75. office365/common/cross_tenant_calendar_sharing_free_busy_detail.py +7 -0
  76. office365/common/cross_tenant_calendar_sharing_free_busy_reviewer.py +7 -0
  77. office365/common/cross_tenant_calendar_sharing_free_busy_simple.py +7 -0
  78. office365/common/cross_tenant_identity_sync_policy_partner.py +35 -0
  79. office365/common/cross_tenant_mail_tips_all.py +7 -0
  80. office365/common/cross_tenant_mail_tips_limited.py +7 -0
  81. office365/common/cross_tenant_migration.py +7 -0
  82. office365/common/cross_tenant_open_profile_card.py +7 -0
  83. office365/common/cross_tenant_places_desk_booking.py +7 -0
  84. office365/common/cross_tenant_places_room_booking.py +7 -0
  85. office365/common/custom_authentication_extension.py +25 -0
  86. office365/common/custom_data_provided_resource.py +25 -0
  87. office365/common/custom_data_provided_resource_access_review_upload_session.py +7 -0
  88. office365/common/data_source_configuration.py +19 -0
  89. office365/common/delta_participants.py +31 -0
  90. office365/common/desk.py +51 -0
  91. office365/common/dictionaries.py +10 -0
  92. office365/common/directory_object_partner_reference.py +32 -0
  93. office365/common/domain_dns_mx_record.py +21 -0
  94. office365/common/domain_dns_srv_record.py +41 -0
  95. office365/common/domain_dns_txt_record.py +16 -0
  96. office365/common/domain_dns_unavailable_record.py +16 -0
  97. office365/common/drive_protection_unit.py +26 -0
  98. office365/common/drive_protection_units_bulk_addition_job.py +20 -0
  99. office365/common/drive_restore_artifact.py +26 -0
  100. office365/common/drive_restore_artifacts_bulk_addition_request.py +20 -0
  101. office365/common/edition_upgrade_configuration.py +47 -0
  102. office365/common/email_authentication_method_configuration.py +44 -0
  103. office365/common/emergency_call_event.py +31 -0
  104. office365/common/end_user_settings.py +32 -0
  105. office365/common/endpoint.py +36 -0
  106. office365/common/engagement_async_operation.py +31 -0
  107. office365/common/engagement_conversation_discussion_message.py +7 -0
  108. office365/common/engagement_conversation_question_message.py +16 -0
  109. office365/common/engagement_conversation_system_message.py +7 -0
  110. office365/common/engagement_role.py +33 -0
  111. office365/common/engagement_role_member.py +33 -0
  112. office365/common/enrollment_troubleshooting_event.py +63 -0
  113. office365/common/enterprise_code_signing_certificate.py +57 -0
  114. office365/common/error_detail.py +16 -0
  115. office365/common/event_message_request.py +54 -0
  116. office365/common/event_message_response.py +29 -0
  117. office365/common/exchange_protection_policy.py +60 -0
  118. office365/common/exchange_restore_session.py +68 -0
  119. office365/common/exchange_settings.py +16 -0
  120. office365/common/external_authentication_method.py +21 -0
  121. office365/common/external_authentication_method_configuration.py +54 -0
  122. office365/common/external_domain_name.py +7 -0
  123. office365/common/external_users_self_service_sign_up_events_flow.py +85 -0
  124. office365/common/fido2_authentication_method_configuration.py +72 -0
  125. office365/common/fido2_combination_configuration.py +15 -0
  126. office365/common/fixture_map.py +16 -0
  127. office365/common/floor.py +16 -0
  128. office365/common/footprint_map.py +7 -0
  129. office365/common/granular_drive_restore_artifact.py +16 -0
  130. office365/common/granular_mailbox_restore_artifact.py +21 -0
  131. office365/common/granular_restore_artifact_base.py +62 -0
  132. office365/common/granular_site_restore_artifact.py +16 -0
  133. office365/common/human_security_fraud_protection_provider.py +21 -0
  134. office365/common/identity_built_in_user_flow_attribute.py +7 -0
  135. office365/common/identity_custom_user_flow_attribute.py +7 -0
  136. office365/common/image_info.py +17 -0
  137. office365/common/imported_windows_autopilot_device_identity_upload.py +52 -0
  138. office365/common/intune_brand.py +29 -0
  139. office365/common/ip_named_location.py +27 -0
  140. office365/common/ipv4_range.py +15 -0
  141. office365/common/ipv6_range.py +15 -0
  142. office365/common/key_value.py +15 -0
  143. office365/common/learning_assignment.py +48 -0
  144. office365/common/level_map.py +52 -0
  145. office365/common/mailbox.py +26 -0
  146. office365/common/mailbox_folder.py +104 -0
  147. office365/common/mailbox_item.py +61 -0
  148. office365/common/mailbox_protection_rule.py +16 -0
  149. office365/common/mailbox_protection_unit.py +26 -0
  150. office365/common/mailbox_protection_units_bulk_addition_job.py +20 -0
  151. office365/common/mailbox_restore_artifact.py +26 -0
  152. office365/common/mailbox_restore_artifacts_bulk_addition_request.py +20 -0
  153. office365/common/managed_android_lob_app.py +40 -0
  154. office365/common/managed_android_store_app.py +35 -0
  155. office365/common/managed_app_status_raw.py +21 -0
  156. office365/common/managed_ios_lob_app.py +56 -0
  157. office365/common/managed_ios_store_app.py +45 -0
  158. office365/common/managed_mobile_lob_app.py +45 -0
  159. office365/common/microsoft_account_user_conversation_member.py +16 -0
  160. office365/common/microsoft_authenticator_authentication_method_configuration.py +51 -0
  161. office365/common/microsoft_authenticator_authentication_method_target.py +25 -0
  162. office365/common/microsoft_store_for_business_app.py +45 -0
  163. office365/common/mime_content.py +15 -0
  164. office365/common/mute_participant_operation.py +8 -0
  165. office365/common/oidc_identity_provider.py +69 -0
  166. office365/common/on_attribute_collection_listener.py +25 -0
  167. office365/common/on_attribute_collection_start_custom_extension.py +7 -0
  168. office365/common/on_attribute_collection_start_listener.py +25 -0
  169. office365/common/on_attribute_collection_submit_custom_extension.py +7 -0
  170. office365/common/on_attribute_collection_submit_listener.py +25 -0
  171. office365/common/on_authentication_method_load_start_listener.py +25 -0
  172. office365/common/on_email_otp_send_listener.py +21 -0
  173. office365/common/on_fraud_protection_load_start_listener.py +25 -0
  174. office365/common/on_interactive_auth_flow_start_listener.py +25 -0
  175. office365/common/on_otp_send_custom_extension.py +7 -0
  176. office365/common/on_password_submit_custom_extension.py +7 -0
  177. office365/common/on_password_submit_listener.py +25 -0
  178. office365/common/on_token_issuance_start_listener.py +25 -0
  179. office365/common/on_user_create_start_listener.py +25 -0
  180. office365/common/on_verified_id_claim_validation_listener.py +25 -0
  181. office365/common/operation.py +35 -0
  182. office365/common/os_version_count.py +17 -0
  183. office365/common/participant_joining_notification.py +22 -0
  184. office365/common/participant_left_notification.py +27 -0
  185. office365/common/passkey_authentication_method_target.py +15 -0
  186. office365/common/passkey_profile.py +50 -0
  187. office365/common/phone_user_conversation_member.py +16 -0
  188. office365/common/play_prompt_operation.py +8 -0
  189. office365/common/privacy.py +32 -0
  190. office365/common/prompt.py +10 -0
  191. office365/common/protection_units_bulk_job_base.py +64 -0
  192. office365/common/provision_response.py +15 -0
  193. office365/common/proxied_domain.py +15 -0
  194. office365/common/qr_code.py +46 -0
  195. office365/common/qr_code_pin_authentication_method.py +41 -0
  196. office365/common/qr_code_pin_authentication_method_configuration.py +42 -0
  197. office365/common/qr_pin.py +32 -0
  198. office365/common/reading_assignment_submission.py +123 -0
  199. office365/common/reading_coach_passage.py +63 -0
  200. office365/common/record_operation.py +22 -0
  201. office365/common/reflect_check_in_response.py +70 -0
  202. office365/common/related_tenants_refresh_request.py +16 -0
  203. office365/common/reports_root.py +79 -0
  204. office365/common/request.py +47 -0
  205. office365/common/reseller_delegated_admin_relationship.py +21 -0
  206. office365/common/restore_artifact_base.py +59 -0
  207. office365/common/restore_artifacts_bulk_request_base.py +104 -0
  208. office365/common/restore_point.py +43 -0
  209. office365/common/restore_session_base.py +93 -0
  210. office365/common/role_assignment.py +40 -0
  211. office365/common/role_definition.py +52 -0
  212. office365/common/saml_or_ws_fed_external_domain_federation.py +28 -0
  213. office365/common/section.py +7 -0
  214. office365/common/section_map.py +16 -0
  215. office365/common/send_dtmf_tones_operation.py +26 -0
  216. office365/common/service_announcement_attachment.py +37 -0
  217. office365/common/setting_source.py +17 -0
  218. office365/common/shared_pc_configuration.py +88 -0
  219. office365/common/sharepoint_embedded_configuration.py +14 -0
  220. office365/common/site_protection_rule.py +16 -0
  221. office365/common/site_protection_unit.py +26 -0
  222. office365/common/site_protection_units_bulk_addition_job.py +20 -0
  223. office365/common/site_restore_artifact.py +26 -0
  224. office365/common/site_restore_artifacts_bulk_addition_request.py +20 -0
  225. office365/common/skype_for_business_user_conversation_member.py +21 -0
  226. office365/common/skype_user_conversation_member.py +16 -0
  227. office365/common/software_oath_authentication_method.py +16 -0
  228. office365/common/software_oath_authentication_method_configuration.py +32 -0
  229. office365/common/speaker_assignment_submission.py +108 -0
  230. office365/common/storage_quota_breakdown.py +26 -0
  231. office365/common/subscribe_to_tone_operation.py +8 -0
  232. office365/common/task_file_attachment.py +11 -0
  233. office365/common/teamwork_hosted_content.py +21 -0
  234. office365/common/temporary_access_pass_authentication_method_configuration.py +57 -0
  235. office365/common/unit_map.py +16 -0
  236. office365/common/verifiable_credential_authentication_method_target.py +15 -0
  237. office365/common/verifiable_credentials_authentication_method_configuration.py +34 -0
  238. office365/common/voice_authentication_method_configuration.py +37 -0
  239. office365/common/web_app.py +21 -0
  240. office365/common/what_if_analysis_result.py +30 -0
  241. office365/communications/aad_user_conversation_member_result.py +14 -0
  242. office365/communications/aad_user_notification_recipient.py +14 -0
  243. office365/communications/accept_join_response.py +10 -0
  244. office365/communications/app_hosted_media_config.py +14 -0
  245. office365/communications/application_identity.py +15 -0
  246. office365/communications/application_instance_identity.py +15 -0
  247. office365/communications/attendance_interval.py +17 -0
  248. office365/communications/audio_conferencing.py +20 -0
  249. office365/communications/azure_communication_services_user_identity.py +14 -0
  250. office365/communications/broadcast_meeting_caption_settings.py +17 -0
  251. office365/communications/call_participant_info.py +15 -0
  252. office365/communications/callrecords/administrative_unit_info.py +14 -0
  253. office365/communications/callrecords/call_record.py +31 -1
  254. office365/communications/callrecords/client_user_agent.py +19 -0
  255. office365/communications/callrecords/collection.py +8 -0
  256. office365/communications/callrecords/device_info.py +34 -0
  257. office365/communications/callrecords/direct_routing_log_row.py +47 -0
  258. office365/communications/callrecords/endpoint.py +8 -1
  259. office365/communications/callrecords/failure_info.py +16 -0
  260. office365/communications/callrecords/feedback_token_set.py +10 -0
  261. office365/communications/callrecords/media.py +23 -0
  262. office365/communications/callrecords/media_stream.py +65 -0
  263. office365/communications/callrecords/network_info.py +53 -0
  264. office365/communications/callrecords/organizer.py +7 -0
  265. office365/communications/callrecords/participant.py +7 -0
  266. office365/communications/callrecords/participant_base.py +31 -0
  267. office365/communications/callrecords/participant_endpoint.py +23 -0
  268. office365/communications/callrecords/pstn_call_log_row.py +40 -0
  269. office365/communications/callrecords/segment.py +34 -0
  270. office365/communications/callrecords/service_endpoint.py +10 -0
  271. office365/communications/callrecords/service_user_agent.py +15 -0
  272. office365/communications/callrecords/session.py +13 -1
  273. office365/communications/callrecords/trace_route_hop.py +20 -0
  274. office365/communications/callrecords/user_agent.py +15 -0
  275. office365/communications/callrecords/user_feedback.py +18 -0
  276. office365/communications/callrecords/user_identity.py +14 -0
  277. office365/communications/callrecords/wifi_band.py +15 -0
  278. office365/communications/callrecords/wifi_radio_type.py +18 -0
  279. office365/communications/calls/ai_insight.py +63 -0
  280. office365/communications/calls/audio_routing_group.py +32 -0
  281. office365/communications/calls/call.py +84 -5
  282. office365/communications/calls/content_sharing_session.py +7 -0
  283. office365/communications/calls/ended_event_message_detail.py +6 -0
  284. office365/communications/calls/event.py +40 -0
  285. office365/communications/calls/incoming_context.py +14 -1
  286. office365/communications/calls/invitation_participant_info.py +4 -0
  287. office365/communications/calls/media_state.py +15 -0
  288. office365/communications/calls/options.py +8 -0
  289. office365/communications/calls/participant.py +48 -1
  290. office365/communications/calls/participant_info.py +17 -1
  291. office365/communications/calls/route.py +13 -1
  292. office365/communications/calls/transcription_info.py +17 -0
  293. office365/communications/chat_members_notification_recipient.py +14 -0
  294. office365/communications/chat_renamed_event_message_detail.py +17 -0
  295. office365/communications/chat_restrictions.py +14 -0
  296. office365/communications/cloud_communications.py +35 -1
  297. office365/communications/comms_notification.py +15 -0
  298. office365/communications/comms_notifications.py +18 -0
  299. office365/communications/conversation_member_role_updated_event_message_detail.py +19 -0
  300. office365/communications/emergency_caller_info.py +19 -0
  301. office365/communications/encrypted_identity.py +10 -0
  302. office365/communications/engagement_identity_set.py +16 -0
  303. office365/communications/guest_identity.py +14 -0
  304. office365/communications/incoming_call_options.py +10 -0
  305. office365/communications/invite_new_bot_response.py +14 -0
  306. office365/communications/join_meeting_id_settings.py +16 -0
  307. office365/communications/max_work_location_details.py +15 -0
  308. office365/communications/media_config.py +10 -0
  309. office365/communications/media_info.py +15 -0
  310. office365/communications/media_prompt.py +15 -0
  311. office365/communications/meetings/join_meeting_id_info.py +13 -0
  312. office365/communications/onlinemeetings/attendance_record.py +62 -0
  313. office365/communications/onlinemeetings/base.py +86 -5
  314. office365/communications/onlinemeetings/broadcast_settings.py +6 -1
  315. office365/communications/onlinemeetings/chatmode.py +8 -9
  316. office365/communications/onlinemeetings/collection.py +9 -1
  317. office365/communications/onlinemeetings/engagement_conversation.py +16 -2
  318. office365/communications/onlinemeetings/meeting_attendance_report.py +64 -0
  319. office365/communications/onlinemeetings/online_meeting_info.py +6 -0
  320. office365/communications/onlinemeetings/restricted.py +16 -0
  321. office365/communications/onlinemeetings/sensitivity_label_assignment.py +14 -0
  322. office365/communications/operations/comms.py +22 -1
  323. office365/communications/organizer_meeting_info.py +15 -0
  324. office365/communications/out_of_office_settings.py +15 -0
  325. office365/communications/outgoing_call_options.py +10 -0
  326. office365/communications/participant_joining_response.py +10 -0
  327. office365/communications/phone_identity.py +10 -0
  328. office365/communications/presences/presence.py +22 -1
  329. office365/communications/presences/status_message.py +4 -0
  330. office365/communications/quotas.py +66 -0
  331. office365/communications/recording_info.py +17 -0
  332. office365/communications/reject_join_response.py +15 -0
  333. office365/communications/removed_state.py +14 -0
  334. office365/communications/service_hosted_media_config.py +16 -0
  335. office365/communications/teleconference_device_audio_quality.py +10 -0
  336. office365/communications/teleconference_device_media_quality.py +38 -0
  337. office365/communications/teleconference_device_screen_sharing_quality.py +10 -0
  338. office365/communications/teleconference_device_video_quality.py +17 -0
  339. office365/communications/teleconferencedevicequality.py +32 -1
  340. office365/communications/token_meeting_info.py +14 -0
  341. office365/communications/tone_info.py +16 -0
  342. office365/communications/user_identity.py +14 -0
  343. office365/communications/user_work_location.py +18 -0
  344. office365/communications/virtualevents/external_information.py +15 -0
  345. office365/communications/virtualevents/external_registration_information.py +15 -0
  346. office365/communications/virtualevents/presenter.py +35 -0
  347. office365/communications/virtualevents/presenter_details.py +21 -0
  348. office365/communications/virtualevents/presenter_info.py +17 -0
  349. office365/communications/virtualevents/registration.py +109 -0
  350. office365/communications/virtualevents/registration_configuration.py +52 -0
  351. office365/communications/virtualevents/registration_custom_question.py +31 -0
  352. office365/communications/virtualevents/registration_predefined_question.py +25 -0
  353. office365/communications/virtualevents/registration_question_answer.py +19 -0
  354. office365/communications/virtualevents/registration_question_base.py +21 -0
  355. office365/communications/virtualevents/root.py +21 -0
  356. office365/communications/virtualevents/session.py +35 -0
  357. office365/communications/virtualevents/settings.py +6 -0
  358. office365/communications/virtualevents/townhall.py +83 -0
  359. office365/communications/virtualevents/townhall_registration_configuration.py +7 -0
  360. office365/communications/virtualevents/virtual_event.py +81 -1
  361. office365/communications/virtualevents/webinar.py +65 -0
  362. office365/communications/virtualevents/webinar_registration_configuration.py +7 -0
  363. office365/copilot/action_result_part.py +4 -1
  364. office365/copilot/admin_catalog.py +28 -0
  365. office365/copilot/admin_limited_mode.py +21 -0
  366. office365/copilot/admin_setting.py +24 -0
  367. office365/copilot/ai_interaction_history.py +9 -0
  368. office365/copilot/ai_online_meeting.py +26 -0
  369. office365/copilot/ai_user.py +39 -0
  370. office365/copilot/copilot_package_request_status.py +14 -0
  371. office365/copilot/copilot_package_request_type.py +15 -0
  372. office365/copilot/package.py +153 -0
  373. office365/copilot/package_access_entity.py +3 -0
  374. office365/copilot/package_detail.py +92 -0
  375. office365/copilot/report_root.py +9 -0
  376. office365/copilot/retrieval_data_source.py +2 -0
  377. office365/delta_collection.py +37 -1
  378. office365/directory/administrative_unit.py +51 -1
  379. office365/directory/allowed_value.py +16 -0
  380. office365/directory/application_permission_type.py +13 -0
  381. office365/directory/application_resource_permission.py +18 -0
  382. office365/directory/applications/application.py +217 -14
  383. office365/directory/applications/applications_required_resource_access.py +21 -0
  384. office365/directory/applications/collection.py +40 -2
  385. office365/directory/applications/custom_security_attribute_exemption.py +2 -2
  386. office365/directory/applications/instance_resource_access.py +19 -0
  387. office365/directory/approval_settings.py +22 -0
  388. office365/directory/audit/provisioning/object_summary.py +19 -3
  389. office365/directory/audit/signins/activity.py +2 -2
  390. office365/directory/authentication/attributecollection/start_custom_extension_handler.py +8 -0
  391. office365/directory/authentication/attributecollection/submit_custom_extension_handler.py +8 -0
  392. office365/directory/authentication/authentication.py +124 -4
  393. office365/directory/authentication/behaviors.py +2 -0
  394. office365/directory/authentication/conditions/application.py +13 -0
  395. office365/directory/authentication/conditions/event_listener.py +32 -0
  396. office365/directory/authentication/error_correction_level.py +2 -0
  397. office365/directory/authentication/fraud_protection_provider.py +16 -0
  398. office365/directory/authentication/fraud_protection_provider_configuration.py +8 -0
  399. office365/directory/authentication/methods/fido.py +46 -1
  400. office365/directory/authentication/methods/method.py +12 -0
  401. office365/directory/authentication/methods/microsoft_authenticator.py +34 -0
  402. office365/directory/authentication/methods/phone.py +30 -0
  403. office365/directory/authentication/password_reset_response.py +4 -0
  404. office365/directory/authentication/platform_credential_authentication_method.py +51 -0
  405. office365/directory/authentication/qr_code_image_details.py +5 -0
  406. office365/directory/authentication/temporary_access_pass_authentication_method.py +42 -0
  407. office365/directory/authentication/windows_hello_for_business_authentication_method.py +39 -0
  408. office365/directory/b2b_registration_metrics.py +42 -0
  409. office365/directory/b2b_registration_metrics_initial.py +17 -0
  410. office365/directory/b2b_registration_metrics_recent.py +17 -0
  411. office365/directory/b2b_sign_in_activity_metrics.py +42 -0
  412. office365/directory/b2b_sign_in_activity_metrics_initial.py +17 -0
  413. office365/directory/b2b_sign_in_activity_metrics_recent.py +17 -0
  414. office365/directory/certificates/auth_pki.py +50 -0
  415. office365/directory/certificates/authority_detail.py +74 -0
  416. office365/directory/certificates/x509/authentication_method_configuration.py +98 -0
  417. office365/directory/certificates/x509/combination_configuration.py +20 -0
  418. office365/directory/claim_binding.py +17 -0
  419. office365/directory/claim_binding_source.py +12 -0
  420. office365/directory/claim_validation.py +15 -0
  421. office365/directory/credential.py +106 -0
  422. office365/directory/cross_cloud_azure_active_directory_tenant.py +16 -0
  423. office365/directory/custom_security_attribute_definition.py +65 -0
  424. office365/directory/datapolicy/operation.py +2 -1
  425. office365/directory/delegated_administration_role_assignment.py +24 -0
  426. office365/directory/delegated_administration_role_assignment_snapshot.py +20 -0
  427. office365/directory/delegatedadmin/access_assignment.py +60 -0
  428. office365/directory/delegatedadmin/access_container.py +18 -0
  429. office365/directory/delegatedadmin/access_details.py +16 -0
  430. office365/directory/delegatedadmin/customer.py +44 -0
  431. office365/directory/delegatedadmin/relationship.py +136 -0
  432. office365/directory/delegatedadmin/relationship_customer_participant.py +15 -0
  433. office365/directory/delegatedadmin/relationship_operation.py +56 -0
  434. office365/directory/delegatedadmin/relationship_request.py +48 -0
  435. office365/directory/delegatedadmin/service_management_detail.py +21 -0
  436. office365/directory/delegatedadmin/service_provider_constraints.py +28 -0
  437. office365/directory/device_local_credential_info.py +18 -1
  438. office365/directory/directory.py +86 -0
  439. office365/directory/domains/collection.py +57 -0
  440. office365/directory/domains/dns_cname_record.py +13 -0
  441. office365/directory/domains/dns_record.py +47 -0
  442. office365/directory/domains/domain.py +93 -0
  443. office365/directory/domains/internal_domain_federation.py +78 -0
  444. office365/directory/drifted_property.py +17 -0
  445. office365/directory/entity_type_and_ids.py +17 -0
  446. office365/directory/external_domain_federation.py +16 -0
  447. office365/directory/external_sponsors.py +10 -0
  448. office365/directory/external_token_based_sap_iag_connection_info.py +19 -0
  449. office365/directory/governance_invitation.py +42 -0
  450. office365/directory/governance_relationship.py +65 -0
  451. office365/directory/governance_request.py +76 -0
  452. office365/directory/groups/collection.py +19 -2
  453. office365/directory/groups/group.py +64 -11
  454. office365/directory/groups/setting.py +14 -1
  455. office365/directory/groups/setting_template.py +31 -0
  456. office365/directory/identities/api_connector.py +18 -0
  457. office365/directory/identities/authentication_events_flow.py +35 -0
  458. office365/directory/identities/b2x_identity_user_flow.py +89 -0
  459. office365/directory/identities/conditional_access_root.py +32 -3
  460. office365/directory/identities/conditional_access_template.py +47 -0
  461. office365/directory/identities/container.py +80 -8
  462. office365/directory/identities/named_location.py +29 -0
  463. office365/directory/identities/on_otp_send_custom_extension_handler.py +6 -0
  464. office365/directory/identities/on_password_migration_custom_extension_handler.py +8 -0
  465. office365/directory/identities/on_token_issuance_start_custom_extension.py +29 -0
  466. office365/directory/identities/on_token_issuance_start_custom_extension_handler.py +8 -0
  467. office365/directory/identities/on_verified_id_claim_validation_custom_extension.py +7 -0
  468. office365/directory/identities/on_verified_id_claim_validation_custom_extension_handler.py +8 -0
  469. office365/directory/identities/provider.py +16 -0
  470. office365/directory/identities/providers/saml_or_wsfed.py +32 -1
  471. office365/directory/identities/riskPrevention/container.py +70 -0
  472. office365/directory/identities/userflows/attribute.py +44 -0
  473. office365/directory/identities/userflows/b2x/user_flow.py +0 -10
  474. office365/directory/identities/userflows/language_configuration.py +11 -0
  475. office365/directory/identities/userflows/user_attribute_assignment.py +67 -0
  476. office365/directory/identities/userflows/user_flow.py +22 -1
  477. office365/directory/identities/verified_id_root.py +28 -0
  478. office365/directory/identities/web_application_firewall_provider.py +16 -0
  479. office365/directory/identities/web_application_firewall_verification_model.py +69 -0
  480. office365/directory/identity_set.py +19 -0
  481. office365/directory/identitygovernance/access_package_suggestion.py +43 -0
  482. office365/directory/identitygovernance/accessreview/context_data.py +10 -0
  483. office365/directory/identitygovernance/accessreview/context_data_base.py +15 -0
  484. office365/directory/identitygovernance/accessreview/custom_data_provided_resource_upload_session_request.py +4 -1
  485. office365/directory/identitygovernance/accessreview/history/definition.py +23 -3
  486. office365/directory/identitygovernance/accessreview/instance.py +49 -3
  487. office365/directory/identitygovernance/accessreview/instance_decision_item.py +49 -1
  488. office365/directory/identitygovernance/accessreview/instance_decision_item_apply_result.py +16 -0
  489. office365/directory/identitygovernance/accessreview/instance_decision_item_custom_data_provided_resource.py +16 -0
  490. office365/directory/identitygovernance/accessreview/instance_decision_item_permission.py +17 -0
  491. office365/directory/identitygovernance/accessreview/instance_decision_item_resource.py +2 -0
  492. office365/directory/identitygovernance/accessreview/principal_scope.py +5 -0
  493. office365/directory/identitygovernance/accessreview/principal_scope_type.py +15 -0
  494. office365/directory/identitygovernance/accessreview/resource_scope.py +5 -0
  495. office365/directory/identitygovernance/accessreview/resource_scope_type.py +16 -0
  496. office365/directory/identitygovernance/accessreview/reviewer_scope.py +5 -0
  497. office365/directory/identitygovernance/accessreview/reviewer_scope_type.py +18 -0
  498. office365/directory/identitygovernance/accessreview/schedule_definition.py +64 -3
  499. office365/directory/identitygovernance/accessreview/set.py +34 -1
  500. office365/directory/identitygovernance/accessreview/stage.py +31 -1
  501. office365/directory/identitygovernance/activities_container.py +30 -0
  502. office365/directory/identitygovernance/apply_decision_context_data.py +10 -0
  503. office365/directory/identitygovernance/awaited_workflow_processing_result.py +6 -1
  504. office365/directory/identitygovernance/content_activity.py +35 -0
  505. office365/directory/identitygovernance/custom_callout_extension_type.py +15 -0
  506. office365/directory/identitygovernance/custom_extension_resource_type.py +14 -0
  507. office365/directory/identitygovernance/custom_task_extension.py +18 -1
  508. office365/directory/identitygovernance/custom_task_extension_callout_data.py +13 -2
  509. office365/directory/identitygovernance/custom_task_extension_reply_mode.py +14 -0
  510. office365/directory/identitygovernance/custom_task_extension_response_data.py +1 -1
  511. office365/directory/identitygovernance/data.py +10 -0
  512. office365/directory/identitygovernance/data_security_and_governance.py +23 -0
  513. office365/directory/identitygovernance/deleted_item_container.py +17 -0
  514. office365/directory/identitygovernance/entitlementmanagement/accesspackage/assignment.py +37 -3
  515. office365/directory/identitygovernance/entitlementmanagement/accesspackage/assignment_policy.py +109 -3
  516. office365/directory/identitygovernance/entitlementmanagement/accesspackage/assignment_request.py +64 -4
  517. office365/directory/identitygovernance/entitlementmanagement/accesspackage/catalog.py +74 -2
  518. office365/directory/identitygovernance/entitlementmanagement/accesspackage/custom_data_provided_resource_file.py +27 -0
  519. office365/directory/identitygovernance/entitlementmanagement/accesspackage/custom_data_provided_resource_upload_session.py +80 -0
  520. office365/directory/identitygovernance/entitlementmanagement/accesspackage/multiple_choice_question.py +18 -1
  521. office365/directory/identitygovernance/entitlementmanagement/accesspackage/package.py +51 -1
  522. office365/directory/identitygovernance/entitlementmanagement/accesspackage/question.py +18 -1
  523. office365/directory/identitygovernance/entitlementmanagement/accesspackage/resource.py +52 -1
  524. office365/directory/identitygovernance/entitlementmanagement/accesspackage/resource_environment.py +11 -1
  525. office365/directory/identitygovernance/entitlementmanagement/accesspackage/resource_role.py +11 -1
  526. office365/directory/identitygovernance/entitlementmanagement/accesspackage/resource_role_scope.py +32 -0
  527. office365/directory/identitygovernance/entitlementmanagement/accesspackage/subject.py +31 -1
  528. office365/directory/identitygovernance/entitlementmanagement/available_access_package.py +42 -0
  529. office365/directory/identitygovernance/entitlementmanagement/connected_organization.py +16 -1
  530. office365/directory/identitygovernance/entitlementmanagement/control_configuration.py +37 -0
  531. office365/directory/identitygovernance/entitlementmanagement/entitlement_management.py +246 -1
  532. office365/directory/identitygovernance/entitlementmanagement/external_origin_resource_connector.py +58 -0
  533. office365/directory/identitygovernance/governance.py +39 -5
  534. office365/directory/identitygovernance/insights.py +3 -1
  535. office365/directory/identitygovernance/lifecycle_management_settings.py +15 -1
  536. office365/directory/identitygovernance/lifecycle_workflows_container.py +35 -2
  537. office365/directory/identitygovernance/lifecycletaskcategory.py +4 -0
  538. office365/directory/identitygovernance/lifecycleworkflows/category.py +4 -0
  539. office365/directory/identitygovernance/privilegedaccess/group.py +21 -0
  540. office365/directory/identitygovernance/privilegedaccess/group_resource.py +7 -0
  541. office365/directory/identitygovernance/privilegedaccess/role_management_custom_callout_extension.py +43 -0
  542. office365/directory/identitygovernance/privilegedaccess/root.py +27 -1
  543. office365/directory/identitygovernance/privilegedaccess/schedule/schedule.py +13 -1
  544. office365/directory/identitygovernance/privilegedaccess/schedule_request.py +22 -2
  545. office365/directory/identitygovernance/run.py +36 -5
  546. office365/directory/identitygovernance/subject_processing_result.py +121 -0
  547. office365/directory/identitygovernance/subject_type.py +13 -0
  548. office365/directory/identitygovernance/task_processing_result.py +18 -2
  549. office365/directory/identitygovernance/termsofuse/agreement.py +26 -4
  550. office365/directory/identitygovernance/termsofuse/agreement_file.py +4 -2
  551. office365/directory/identitygovernance/termsofuse/agreement_file_localization.py +4 -2
  552. office365/directory/identitygovernance/termsofuse/agreement_file_properties.py +15 -1
  553. office365/directory/identitygovernance/termsofuse/agreement_file_version.py +4 -2
  554. office365/directory/identitygovernance/user_data_security_and_governance.py +34 -0
  555. office365/directory/identitygovernance/user_protection_scope_container.py +9 -0
  556. office365/directory/identitygovernance/workflow/base.py +19 -3
  557. office365/directory/identitygovernance/workflow/executiontype.py +4 -0
  558. office365/directory/identitygovernance/workflow/setting.py +17 -0
  559. office365/directory/identitygovernance/workflow/version.py +28 -0
  560. office365/directory/identitygovernance/workflow/workflow.py +127 -0
  561. office365/directory/inheritable_permission.py +28 -0
  562. office365/directory/insights/identity.py +15 -0
  563. office365/directory/insights/resource_reference.py +4 -0
  564. office365/directory/insights/shared.py +27 -0
  565. office365/directory/insights/sharing_detail.py +4 -0
  566. office365/directory/insights/trending.py +22 -1
  567. office365/directory/insights/usage_details.py +4 -0
  568. office365/directory/insights/used.py +18 -0
  569. office365/directory/internal/sponsors.py +10 -0
  570. office365/directory/key_credential.py +9 -23
  571. office365/directory/licenses/collection.py +30 -0
  572. office365/directory/licenses/subscribed_sku.py +3 -0
  573. office365/directory/modified_property.py +16 -0
  574. office365/directory/multi_tenant_application_metrics.py +42 -0
  575. office365/directory/multi_tenant_application_metrics_base.py +27 -0
  576. office365/directory/multi_tenant_application_metrics_initial.py +17 -0
  577. office365/directory/multi_tenant_application_metrics_recent.py +17 -0
  578. office365/directory/multi_tenant_applications_to_provision.py +23 -0
  579. office365/directory/multi_tenant_applications_to_provision_snapshot.py +23 -0
  580. office365/directory/multi_tenant_organization_identity_sync_policy_template.py +37 -0
  581. office365/directory/multi_tenant_organization_join_request_record.py +54 -0
  582. office365/directory/multi_tenant_organization_member.py +76 -0
  583. office365/directory/multi_tenant_organization_partner_configuration_template.py +88 -0
  584. office365/directory/o_auth_consent_app_detail.py +17 -0
  585. office365/directory/objects/object.py +15 -0
  586. office365/directory/on_premises_directory_synchronization.py +37 -0
  587. office365/directory/password_credential.py +10 -23
  588. office365/directory/permissions/grants/condition_set.py +27 -1
  589. office365/directory/permissions/identity.py +4 -0
  590. office365/directory/permissions/identity_set.py +7 -25
  591. office365/directory/permissions/require_permission.py +78 -9
  592. office365/directory/policies/activity_based_timeout_policy.py +7 -0
  593. office365/directory/policies/admin_consent_request.py +50 -0
  594. office365/directory/policies/app_management.py +17 -1
  595. office365/directory/policies/authentication_flows.py +26 -1
  596. office365/directory/policies/authorization.py +12 -0
  597. office365/directory/policies/conditionalaccess/conditional_access.py +82 -0
  598. office365/directory/policies/crosstenant/access.py +43 -0
  599. office365/directory/policies/device_registration.py +69 -0
  600. office365/directory/policies/dlpaction.py +4 -0
  601. office365/directory/policies/feature_rollout.py +38 -0
  602. office365/directory/policies/federated_token_validation_policy.py +21 -0
  603. office365/directory/policies/ownerless_group_policy.py +59 -0
  604. office365/directory/policies/protected_application_metadata.py +1 -1
  605. office365/directory/policies/restrict_access_action_base.py +1 -1
  606. office365/directory/policies/root.py +142 -2
  607. office365/directory/policies/template.py +45 -0
  608. office365/directory/policies/tenant_app_management.py +39 -0
  609. office365/directory/policies/unifiedrolemanagement/policy.py +76 -1
  610. office365/directory/policies/unifiedrolemanagement/unified_role_assignment_schedule_request.py +145 -0
  611. office365/directory/policies/verified_id_profile_configuration.py +13 -1
  612. office365/directory/policies/verified_id_usage_configuration.py +5 -0
  613. office365/directory/profile_card_annotation.py +19 -0
  614. office365/directory/profile_source_localization.py +16 -0
  615. office365/directory/protection/bitlocker.py +32 -0
  616. office365/directory/protection/bitlocker_recovery_key.py +37 -0
  617. office365/directory/protection/information.py +18 -0
  618. office365/directory/protection/policy/base.py +82 -0
  619. office365/directory/protection/policy/one_drive_for_business.py +42 -0
  620. office365/directory/protection/riskyusers/risky_service_principal_history_item.py +15 -1
  621. office365/directory/protection/root.py +42 -0
  622. office365/directory/protection/rules/base.py +72 -0
  623. office365/directory/protection/rules/drive.py +13 -0
  624. office365/directory/protection/threatassessment/requests/email_file.py +26 -1
  625. office365/directory/protection/threatassessment/requests/file.py +11 -0
  626. office365/directory/protection/threatassessment/requests/mail.py +32 -0
  627. office365/directory/protection/threatassessment/requests/request.py +52 -1
  628. office365/directory/protection/threatassessment/requests/threat_assessment_result.py +36 -0
  629. office365/directory/protection/threatassessment/requests/url.py +6 -0
  630. office365/directory/quotas.py +34 -0
  631. office365/directory/recovery/change_object_base.py +31 -0
  632. office365/directory/recovery/job.py +26 -0
  633. office365/directory/recovery/job_base.py +59 -0
  634. office365/directory/recovery/job_entity_name_and_ids_filter.py +18 -0
  635. office365/directory/recovery/job_entity_names_filter.py +18 -0
  636. office365/directory/recovery/job_filtering_criteria_base.py +10 -0
  637. office365/directory/recovery/preview_job.py +9 -0
  638. office365/directory/recovery/recovery.py +37 -0
  639. office365/directory/related_tenant.py +88 -0
  640. office365/directory/related_tenants_refresh_status.py +17 -0
  641. office365/directory/relationship_creation_type.py +13 -0
  642. office365/directory/relationship_policy.py +29 -0
  643. office365/directory/relationship_status.py +14 -0
  644. office365/directory/remote_tenant_group.py +37 -0
  645. office365/directory/request_schedule.py +21 -0
  646. office365/directory/request_status.py +14 -0
  647. office365/directory/resource_visualization.py +21 -0
  648. office365/directory/role_template.py +15 -0
  649. office365/directory/role_type.py +15 -0
  650. office365/directory/rolemanagement/app_scope.py +18 -0
  651. office365/directory/rolemanagement/application.py +120 -0
  652. office365/directory/rolemanagement/resource_action.py +4 -0
  653. office365/directory/rolemanagement/roles/collection.py +26 -3
  654. office365/directory/rolemanagement/roles/permission.py +4 -0
  655. office365/directory/rolemanagement/unifiedrole/assignment.py +33 -1
  656. office365/directory/rolemanagement/unifiedrole/definition.py +30 -0
  657. office365/directory/service_provider_constraints.py +7 -0
  658. office365/directory/service_storage_quota_breakdown.py +7 -0
  659. office365/directory/serviceprincipals/approved_client_app.py +16 -0
  660. office365/directory/serviceprincipals/collection.py +48 -4
  661. office365/directory/serviceprincipals/identity.py +14 -0
  662. office365/directory/serviceprincipals/remote_desktop_security_configuration.py +39 -1
  663. office365/directory/serviceprincipals/service_principal.py +330 -19
  664. office365/directory/serviceprincipals/target_device_group.py +16 -0
  665. office365/directory/snapshot.py +50 -0
  666. office365/directory/status.py +15 -0
  667. office365/directory/subscriptions/company.py +75 -0
  668. office365/directory/synchronization/attribute_mapping.py +1 -1
  669. office365/directory/synchronization/attribute_mapping_function_schema.py +1 -1
  670. office365/directory/synchronization/directory_definition.py +1 -1
  671. office365/directory/synchronization/job.py +13 -1
  672. office365/directory/synchronization/job_subject.py +6 -3
  673. office365/directory/synchronization/linked_objects.py +8 -9
  674. office365/directory/synchronization/rule.py +4 -4
  675. office365/directory/synchronization/schema.py +19 -2
  676. office365/directory/synchronization/status.py +1 -1
  677. office365/directory/synchronization/synchronization.py +22 -0
  678. office365/directory/synchronization/template.py +20 -1
  679. office365/directory/tenant_governance.py +98 -0
  680. office365/directory/tenant_governance_policy_template.py +75 -0
  681. office365/directory/tenant_governance_setting.py +21 -0
  682. office365/directory/tenantinformation/multi_organization.py +72 -0
  683. office365/directory/tenantinformation/relationship.py +41 -0
  684. office365/directory/ticket_info.py +15 -0
  685. office365/directory/unified_approval_stage.py +25 -0
  686. office365/directory/unified_rbac_resource_action.py +41 -0
  687. office365/directory/unified_rbac_resource_namespace.py +37 -0
  688. office365/directory/unified_role.py +14 -0
  689. office365/directory/unified_role_assignment_schedule.py +47 -0
  690. office365/directory/unified_role_assignment_schedule_instance.py +60 -0
  691. office365/directory/unified_role_eligibility_schedule.py +26 -0
  692. office365/directory/unified_role_eligibility_schedule_instance.py +32 -0
  693. office365/directory/unified_role_eligibility_schedule_request.py +133 -0
  694. office365/directory/unified_role_management_policy_approval_rule.py +21 -0
  695. office365/directory/unified_role_management_policy_assignment.py +48 -0
  696. office365/directory/unified_role_management_policy_authentication_context_rule.py +21 -0
  697. office365/directory/unified_role_management_policy_custom_extension_rule.py +32 -0
  698. office365/directory/unified_role_management_policy_enablement_rule.py +15 -0
  699. office365/directory/unified_role_management_policy_expiration_rule.py +24 -0
  700. office365/directory/unified_role_management_policy_notification_rule.py +37 -0
  701. office365/directory/unified_role_management_policy_rule.py +25 -0
  702. office365/directory/unified_role_management_policy_rule_target.py +31 -0
  703. office365/directory/unified_role_schedule_base.py +96 -0
  704. office365/directory/unified_role_schedule_instance_base.py +75 -0
  705. office365/directory/unified_root.py +66 -0
  706. office365/directory/unified_storage_quota.py +62 -0
  707. office365/directory/users/activities/activity.py +24 -2
  708. office365/directory/users/activities/history_item.py +42 -1
  709. office365/directory/users/collection.py +17 -0
  710. office365/directory/users/identity.py +4 -0
  711. office365/directory/users/inference_classification.py +23 -0
  712. office365/directory/users/inference_classification_override.py +33 -0
  713. office365/directory/users/item_insights.py +7 -0
  714. office365/directory/users/note.py +101 -0
  715. office365/directory/users/provisioned_plan.py +16 -0
  716. office365/directory/users/settings.py +50 -1
  717. office365/directory/users/storage.py +15 -0
  718. office365/directory/users/user.py +146 -16
  719. office365/directory/users/windows_setting.py +50 -0
  720. office365/directory/users/windows_setting_instance.py +32 -0
  721. office365/directory/users/work_hours_and_locations_setting.py +53 -0
  722. office365/directory/users/work_plan_occurrence.py +56 -0
  723. office365/directory/users/work_plan_recurrence.py +51 -0
  724. office365/directory/verified_id_profile.py +91 -0
  725. office365/directory/visual_info.py +20 -0
  726. office365/education/challenging_word.py +15 -0
  727. office365/education/rubric_criterion.py +10 -0
  728. office365/education/rubric_level.py +15 -0
  729. office365/education/rubric_quality.py +21 -0
  730. office365/education/rubric_quality_feedback_model.py +14 -0
  731. office365/education/rubric_quality_selected_column_model.py +15 -0
  732. office365/entity.py +72 -3
  733. office365/entity_collection.py +35 -4
  734. office365/externalconnectors/acl.py +21 -0
  735. office365/externalconnectors/activity_settings.py +18 -0
  736. office365/externalconnectors/connection_operation.py +17 -2
  737. office365/externalconnectors/connector_type.py +12 -0
  738. office365/externalconnectors/content_category.py +18 -4
  739. office365/externalconnectors/display_template.py +20 -0
  740. office365/externalconnectors/external_activity.py +14 -1
  741. office365/externalconnectors/external_activity_result.py +12 -0
  742. office365/externalconnectors/external_group.py +15 -1
  743. office365/externalconnectors/external_item_content.py +19 -0
  744. office365/externalconnectors/external_item_information_protection_label.py +14 -0
  745. office365/externalconnectors/identity.py +19 -0
  746. office365/externalconnectors/item_id_resolver.py +16 -0
  747. office365/externalconnectors/principal.py +20 -0
  748. office365/externalconnectors/properties.py +10 -0
  749. office365/externalconnectors/property.py +28 -0
  750. office365/externalconnectors/property_rule.py +22 -0
  751. office365/externalconnectors/url_match_info.py +16 -0
  752. office365/externalconnectors/url_to_item_resolver_base.py +14 -0
  753. office365/graph_client.py +184 -35
  754. office365/graph_request.py +56 -4
  755. office365/intune/audit/actor.py +26 -0
  756. office365/intune/audit/event.py +48 -0
  757. office365/intune/audit/property.py +15 -0
  758. office365/intune/audit/resource.py +15 -1
  759. office365/intune/devices/and_app_management_role_assignment.py +15 -0
  760. office365/intune/devices/and_app_management_role_definition.py +7 -0
  761. office365/intune/devices/category.py +18 -0
  762. office365/intune/devices/compliance/android_compliance_policy.py +134 -0
  763. office365/intune/devices/compliance/android_work_profile_compliance_policy.py +134 -0
  764. office365/intune/devices/compliance/compliance.py +7 -0
  765. office365/intune/devices/compliance/information.py +19 -0
  766. office365/intune/devices/compliance/ios_compliance_policy.py +99 -0
  767. office365/intune/devices/compliance/mac_os_compliance_policy.py +114 -0
  768. office365/intune/devices/compliance/management_partner.py +91 -0
  769. office365/intune/devices/compliance/management_partner_assignment.py +17 -0
  770. office365/intune/devices/compliance/policy.py +155 -0
  771. office365/intune/devices/compliance/policy_state.py +61 -0
  772. office365/intune/devices/compliance/setting_state_device_summary.py +56 -0
  773. office365/intune/devices/compliance/windows10_compliance_policy.py +115 -0
  774. office365/intune/devices/compliance/windows10_mobile_compliance_policy.py +100 -0
  775. office365/intune/devices/compliance/windows81_compliance_policy.py +75 -0
  776. office365/intune/devices/compliance/windows_phone81_compliance_policy.py +75 -0
  777. office365/intune/devices/compliance_action_item.py +41 -0
  778. office365/intune/devices/compliance_device_overview.py +47 -0
  779. office365/intune/devices/compliance_device_status.py +52 -0
  780. office365/intune/devices/compliance_policy_assignment.py +25 -0
  781. office365/intune/devices/compliance_policy_device_state_summary.py +56 -0
  782. office365/intune/devices/compliance_policy_setting_state_summary.py +91 -0
  783. office365/intune/devices/compliance_scheduled_action_for_rule.py +39 -0
  784. office365/intune/devices/compliance_setting_state.py +72 -0
  785. office365/intune/devices/compliance_user_overview.py +47 -0
  786. office365/intune/devices/compliance_user_status.py +42 -0
  787. office365/intune/devices/configuration_assignment.py +25 -0
  788. office365/intune/devices/configuration_device_overview.py +47 -0
  789. office365/intune/devices/configuration_device_state_summary.py +46 -0
  790. office365/intune/devices/configuration_device_status.py +52 -0
  791. office365/intune/devices/configuration_state.py +63 -0
  792. office365/intune/devices/configuration_user_overview.py +47 -0
  793. office365/intune/devices/configuration_user_status.py +42 -0
  794. office365/intune/devices/configurations/android/android_lob_app.py +15 -1
  795. office365/intune/devices/configurations/android/android_store_app.py +15 -1
  796. office365/intune/devices/configurations/android/custom_configuration.py +22 -0
  797. office365/intune/devices/configurations/android/general_device_configuration.py +282 -0
  798. office365/intune/devices/configurations/android/minimum_operating_system.py +29 -0
  799. office365/intune/devices/configurations/android/mobile_app_identifier.py +14 -0
  800. office365/intune/devices/configurations/android/work_profile_custom_configuration.py +22 -0
  801. office365/intune/devices/configurations/android/work_profile_general_device_configuration.py +214 -0
  802. office365/intune/devices/configurations/configuration.py +136 -0
  803. office365/intune/devices/configurations/edge_search_engine.py +17 -0
  804. office365/intune/devices/configurations/edge_search_engine_base.py +10 -0
  805. office365/intune/devices/configurations/edge_search_engine_custom.py +14 -0
  806. office365/intune/devices/configurations/ios/certificate_profile.py +7 -0
  807. office365/intune/devices/configurations/ios/custom_configuration.py +26 -0
  808. office365/intune/devices/configurations/ios/features_configuration.py +62 -0
  809. office365/intune/devices/configurations/ios/general/device_configuration.py +761 -0
  810. office365/intune/devices/configurations/ios/home_screen_app.py +14 -0
  811. office365/intune/devices/configurations/ios/home_screen_folder.py +20 -0
  812. office365/intune/devices/configurations/ios/home_screen_folder_page.py +19 -0
  813. office365/intune/devices/configurations/ios/home_screen_item.py +14 -0
  814. office365/intune/devices/configurations/ios/home_screen_page.py +21 -0
  815. office365/intune/devices/configurations/ios/minimum_operating_system.py +21 -0
  816. office365/intune/devices/configurations/ios/network_usage_rule.py +18 -0
  817. office365/intune/devices/configurations/ios/notification_settings.py +25 -0
  818. office365/intune/devices/configurations/ios/update_configuration.py +38 -0
  819. office365/intune/devices/configurations/macos/mac_os_custom_configuration.py +26 -0
  820. office365/intune/devices/configurations/macos/mac_os_device_features_configuration.py +7 -0
  821. office365/intune/devices/configurations/macos/mac_os_general_device_configuration.py +88 -0
  822. office365/intune/devices/configurations/macos/mac_os_minimum_operating_system.py +25 -0
  823. office365/intune/devices/configurations/media_content_rating_australia.py +21 -0
  824. office365/intune/devices/configurations/media_content_rating_canada.py +21 -0
  825. office365/intune/devices/configurations/media_content_rating_france.py +21 -0
  826. office365/intune/devices/configurations/media_content_rating_germany.py +21 -0
  827. office365/intune/devices/configurations/media_content_rating_ireland.py +21 -0
  828. office365/intune/devices/configurations/media_content_rating_japan.py +21 -0
  829. office365/intune/devices/configurations/media_content_rating_new_zealand.py +21 -0
  830. office365/intune/devices/configurations/media_content_rating_united_kingdom.py +21 -0
  831. office365/intune/devices/configurations/media_content_rating_united_states.py +21 -0
  832. office365/intune/devices/configurations/oma_setting.py +16 -0
  833. office365/intune/devices/configurations/oma_setting_base64.py +15 -0
  834. office365/intune/devices/configurations/oma_setting_boolean.py +14 -0
  835. office365/intune/devices/configurations/oma_setting_date_time.py +15 -0
  836. office365/intune/devices/configurations/oma_setting_floating_point.py +14 -0
  837. office365/intune/devices/configurations/oma_setting_integer.py +14 -0
  838. office365/intune/devices/configurations/oma_setting_string.py +14 -0
  839. office365/intune/devices/configurations/oma_setting_string_xml.py +15 -0
  840. office365/intune/devices/configurations/rgb_color.py +16 -0
  841. office365/intune/devices/configurations/windows/bit_locker_removable_drive_policy.py +19 -0
  842. office365/intune/devices/configurations/windows/defender_advanced_threat_protection_configuration.py +21 -0
  843. office365/intune/devices/configurations/windows/firewall_network_profile.py +28 -0
  844. office365/intune/devices/configurations/windows/minimum_operating_system.py +16 -0
  845. office365/intune/devices/configurations/windows/out_of_box_experience_setting.py +25 -0
  846. office365/intune/devices/configurations/windows/phone81_custom_configuration.py +22 -0
  847. office365/intune/devices/configurations/windows/phone81_general_configuration.py +172 -0
  848. office365/intune/devices/configurations/windows/shared_pc_account_manager_policy.py +20 -0
  849. office365/intune/devices/configurations/windows/update_active_hours_install.py +16 -0
  850. office365/intune/devices/configurations/windows/update_for_business_configuration.py +253 -0
  851. office365/intune/devices/configurations/windows/update_install_schedule_type.py +10 -0
  852. office365/intune/devices/configurations/windows/update_scheduled_install.py +19 -0
  853. office365/intune/devices/configurations/windows/windows10_custom_configuration.py +22 -0
  854. office365/intune/devices/configurations/windows/windows10_endpoint_protection_configuration.py +255 -0
  855. office365/intune/devices/configurations/windows/windows10_enrollment_completion_page_configuration.py +16 -0
  856. office365/intune/devices/configurations/windows/windows10_enterprise_modern_app_management_configuration.py +16 -0
  857. office365/intune/devices/configurations/windows/windows10_general_configuration.py +1177 -0
  858. office365/intune/devices/configurations/windows/windows10_network_proxy_server.py +17 -0
  859. office365/intune/devices/configurations/windows/windows10_secure_assessment_configuration.py +36 -0
  860. office365/intune/devices/configurations/windows/windows10_team_general_configuration.py +128 -0
  861. office365/intune/devices/configurations/windows/windows81_general_configuration.py +210 -0
  862. office365/intune/devices/data.py +11 -0
  863. office365/intune/devices/device.py +138 -1
  864. office365/intune/devices/enrollment/configuration.py +48 -1
  865. office365/intune/devices/enrollment/configuration_assignment.py +22 -0
  866. office365/intune/devices/enrollment/limit_configuration.py +13 -0
  867. office365/intune/devices/enrollment_platform_restrictions_configuration.py +61 -0
  868. office365/intune/devices/enrollment_windows_hello_for_business_configuration.py +93 -0
  869. office365/intune/devices/install_state.py +61 -0
  870. office365/intune/devices/log_collection_response.py +60 -0
  871. office365/intune/devices/management/action_result.py +19 -0
  872. office365/intune/devices/management/android_managed_app_registration.py +7 -0
  873. office365/intune/devices/management/app_management.py +157 -3
  874. office365/intune/devices/management/apple_push_notification_certificate.py +52 -0
  875. office365/intune/devices/management/compliance_policy_setting_state.py +28 -0
  876. office365/intune/devices/management/configuration_manager_client_enabled_features.py +19 -0
  877. office365/intune/devices/management/configuration_manager_collection_assignment_target.py +14 -0
  878. office365/intune/devices/management/configuration_setting_state.py +28 -0
  879. office365/intune/devices/management/defender_detected_malware_actions.py +18 -0
  880. office365/intune/devices/management/delete_user_from_shared_apple_device_action_result.py +14 -0
  881. office365/intune/devices/management/detected_app.py +65 -0
  882. office365/intune/devices/management/enrollment_platform_restriction.py +17 -0
  883. office365/intune/devices/management/exchange_access_state_summary.py +18 -0
  884. office365/intune/devices/management/geo_location.py +22 -0
  885. office365/intune/devices/management/group_peer_outlier_recommendation_insight_settings.py +10 -0
  886. office365/intune/devices/management/health_attestation_state.py +46 -0
  887. office365/intune/devices/management/imported_windows_autopilot_device_identity.py +55 -0
  888. office365/intune/devices/management/imported_windows_autopilot_device_identity_state.py +22 -0
  889. office365/intune/devices/management/insight_value_double.py +14 -0
  890. office365/intune/devices/management/insight_value_int.py +14 -0
  891. office365/intune/devices/management/integer_range.py +15 -0
  892. office365/intune/devices/management/ios_managed_app_registration.py +7 -0
  893. office365/intune/devices/management/ios_update_device_status.py +79 -0
  894. office365/intune/devices/management/localized_notification_message.py +37 -0
  895. office365/intune/devices/management/locate_device_action_result.py +15 -0
  896. office365/intune/devices/management/m365_capability_base.py +32 -0
  897. office365/intune/devices/management/m365_capability_inbound_access.py +18 -0
  898. office365/intune/devices/management/m365_capability_resource_scope.py +16 -0
  899. office365/intune/devices/management/m365_capability_resource_scopes.py +23 -0
  900. office365/intune/devices/management/m365_resource_type.py +14 -0
  901. office365/intune/devices/management/managed/app/diagnostic_status.py +15 -0
  902. office365/intune/devices/management/managed/app/operation.py +32 -0
  903. office365/intune/devices/management/managed/app/protections/android.py +31 -1
  904. office365/intune/devices/management/managed/app/protections/default.py +34 -2
  905. office365/intune/devices/management/managed/app/protections/ios.py +34 -2
  906. office365/intune/devices/management/managed/app/protections/targeted.py +22 -1
  907. office365/intune/devices/management/managed/app/protections/targeted_managed_app_policy_assignment.py +25 -0
  908. office365/intune/devices/management/managed/app/protections/windows.py +230 -1
  909. office365/intune/devices/management/managed/app/registration.py +29 -2
  910. office365/intune/devices/management/managed/app_policy_deployment_summary.py +50 -0
  911. office365/intune/devices/management/managed/collection.py +26 -0
  912. office365/intune/devices/management/managed/device_mobile_app_configuration.py +138 -0
  913. office365/intune/devices/management/managed/device_mobile_app_configuration_assignment.py +25 -0
  914. office365/intune/devices/management/managed/device_mobile_app_configuration_device_status.py +52 -0
  915. office365/intune/devices/management/managed/device_mobile_app_configuration_device_summary.py +47 -0
  916. office365/intune/devices/management/managed/device_mobile_app_configuration_user_status.py +42 -0
  917. office365/intune/devices/management/managed/device_mobile_app_configuration_user_summary.py +47 -0
  918. office365/intune/devices/management/managed/device_overview.py +52 -0
  919. office365/intune/devices/management/managed/ebook/e_book_assignment.py +33 -0
  920. office365/intune/devices/management/managed/ebook/ebook.py +72 -1
  921. office365/intune/devices/management/managed/ebook/install_summary.py +41 -0
  922. office365/intune/devices/management/managed/ebook/user_install_state_summary.py +48 -0
  923. office365/intune/devices/management/managed/managed.py +87 -3
  924. office365/intune/devices/management/managed/mobile_app.py +26 -0
  925. office365/intune/devices/management/management.py +995 -6
  926. office365/intune/devices/management/mdm_windows_information_protection_policy.py +7 -0
  927. office365/intune/devices/management/mobile_threat_defense_connector.py +96 -0
  928. office365/intune/devices/management/mobileapps/app_configuration_setting_item.py +17 -0
  929. office365/intune/devices/management/mobileapps/app_list_item.py +17 -0
  930. office365/intune/devices/management/mobileapps/app_log_collection_download_details.py +19 -0
  931. office365/intune/devices/management/mobileapps/app_log_collection_request.py +40 -0
  932. office365/intune/devices/management/mobileapps/apps_installation_options_for_mac.py +15 -0
  933. office365/intune/devices/management/mobileapps/apps_installation_options_for_windows.py +17 -0
  934. office365/intune/devices/management/mobileapps/assignment.py +28 -0
  935. office365/intune/devices/management/mobileapps/content.py +24 -1
  936. office365/intune/devices/management/mobileapps/ios/ios_mobile_app_configuration.py +18 -1
  937. office365/intune/devices/management/mobileapps/ios/iosi_pad_os_web_clip.py +21 -0
  938. office365/intune/devices/management/mobileapps/ios/lob_app.py +58 -0
  939. office365/intune/devices/management/mobileapps/ios/lob_app_assignment_settings.py +16 -0
  940. office365/intune/devices/management/mobileapps/ios/lob_app_provisioning_configuration_assignment.py +25 -0
  941. office365/intune/devices/management/mobileapps/ios/mobile_app_identifier.py +14 -0
  942. office365/intune/devices/management/mobileapps/ios/store_app.py +47 -0
  943. office365/intune/devices/management/mobileapps/ios/store_app_assignment_settings.py +16 -0
  944. office365/intune/devices/management/mobileapps/ios/vpp_app.py +81 -0
  945. office365/intune/devices/management/mobileapps/ios/vpp_app_assignment_settings.py +15 -0
  946. office365/intune/devices/management/mobileapps/ios/vpp_e_book.py +53 -0
  947. office365/intune/devices/management/mobileapps/ios/vpp_e_book_assignment.py +7 -0
  948. office365/intune/devices/management/mobileapps/macos/mac_os_dmg_app.py +49 -0
  949. office365/intune/devices/management/mobileapps/macos/mac_os_included_app.py +15 -0
  950. office365/intune/devices/management/mobileapps/macos/mac_os_lob_app.py +70 -0
  951. office365/intune/devices/management/mobileapps/macos/mac_os_lob_app_assignment_settings.py +14 -0
  952. office365/intune/devices/management/mobileapps/macos/mac_os_lob_child_app.py +16 -0
  953. office365/intune/devices/management/mobileapps/macos/mac_os_microsoft_defender_app.py +7 -0
  954. office365/intune/devices/management/mobileapps/macos/mac_os_microsoft_edge_app.py +25 -0
  955. office365/intune/devices/management/mobileapps/macos/mac_os_office_suite_app.py +7 -0
  956. office365/intune/devices/management/mobileapps/managed/app_policy_deployment_summary_per_app.py +18 -0
  957. office365/intune/devices/management/mobileapps/microsoft_store_for_business_app_assignment_settings.py +14 -0
  958. office365/intune/devices/management/mobileapps/mobile_app.py +31 -2
  959. office365/intune/devices/management/mobileapps/mobile_app_assignment_settings.py +10 -0
  960. office365/intune/devices/management/mobileapps/mobile_app_identifier.py +10 -0
  961. office365/intune/devices/management/mobileapps/mobile_app_install_time_settings.py +17 -0
  962. office365/intune/devices/management/mobileapps/mobile_app_troubleshooting_event.py +28 -0
  963. office365/intune/devices/management/mobileapps/mobile_lob_app.py +20 -1
  964. office365/intune/devices/management/mobileapps/vpp_licensing_type.py +15 -0
  965. office365/intune/devices/management/mobileapps/win32/lob_app.py +115 -0
  966. office365/intune/devices/management/mobileapps/win32/lob_app_assignment_settings.py +35 -0
  967. office365/intune/devices/management/mobileapps/win32/lob_app_auto_update_settings.py +19 -0
  968. office365/intune/devices/management/mobileapps/win32/lob_app_file_system_rule.py +25 -0
  969. office365/intune/devices/management/mobileapps/win32/lob_app_install_experience.py +21 -0
  970. office365/intune/devices/management/mobileapps/win32/lob_app_msi_information.py +23 -0
  971. office365/intune/devices/management/mobileapps/win32/lob_app_power_shell_script_rule.py +32 -0
  972. office365/intune/devices/management/mobileapps/win32/lob_app_product_code_rule.py +19 -0
  973. office365/intune/devices/management/mobileapps/win32/lob_app_registry_rule.py +25 -0
  974. office365/intune/devices/management/mobileapps/win32/lob_app_restart_settings.py +16 -0
  975. office365/intune/devices/management/mobileapps/win32/lob_app_return_code.py +18 -0
  976. office365/intune/devices/management/mobileapps/win32/lob_app_rule.py +17 -0
  977. office365/intune/devices/management/mobileapps/windows/app_x.py +62 -0
  978. office365/intune/devices/management/mobileapps/windows/app_x_app_assignment_settings.py +14 -0
  979. office365/intune/devices/management/mobileapps/windows/microsoft_edge_app.py +30 -0
  980. office365/intune/devices/management/mobileapps/windows/mobile_msi.py +31 -0
  981. office365/intune/devices/management/mobileapps/windows/universal_app_x.py +93 -0
  982. office365/intune/devices/management/mobileapps/windows/universal_app_x_app_assignment_settings.py +14 -0
  983. office365/intune/devices/management/mobileapps/windows/universal_app_x_contained_app.py +16 -0
  984. office365/intune/devices/management/mobileapps/windows/web_app.py +16 -0
  985. office365/intune/devices/management/notification_message_template.py +68 -0
  986. office365/intune/devices/management/obliteration_behavior.py +15 -0
  987. office365/intune/devices/management/on_premises_conditional_access_settings.py +32 -0
  988. office365/intune/devices/management/operating_system_summary.py +25 -0
  989. office365/intune/devices/management/partner_assignment.py +17 -0
  990. office365/intune/devices/management/remote_lock_action_result.py +14 -0
  991. office365/intune/devices/management/remoteassistance/partner.py +41 -0
  992. office365/intune/devices/management/reports/reports.py +27 -0
  993. office365/intune/devices/management/reset_passcode_action_result.py +15 -0
  994. office365/intune/devices/management/resource_operation.py +26 -0
  995. office365/intune/devices/management/rotate_bit_locker_keys_device_action_result.py +14 -0
  996. office365/intune/devices/management/software_update_status_summary.py +86 -0
  997. office365/intune/devices/management/system_browser_enabled_on.py +16 -0
  998. office365/intune/devices/management/targeted_managed_app_configuration.py +68 -0
  999. office365/intune/devices/management/terms_and_conditions.py +87 -0
  1000. office365/intune/devices/management/terms_and_conditions_acceptance_status.py +50 -0
  1001. office365/intune/devices/management/terms_and_conditions_assignment.py +25 -0
  1002. office365/intune/devices/management/update_windows_device_account_action_parameter.py +22 -0
  1003. office365/intune/devices/management/user_last_sign_in_recommendation_insight_setting.py +22 -0
  1004. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_app_health_app_performance_by_app_version_details.py +51 -0
  1005. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_app_health_app_performance_by_app_version_device_id.py +52 -0
  1006. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_app_health_app_performance_by_os_version.py +56 -0
  1007. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_app_health_application_performance.py +56 -0
  1008. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_app_health_device_model_performance.py +50 -0
  1009. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_app_health_device_performance.py +76 -0
  1010. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_app_health_device_performance_details.py +47 -0
  1011. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_app_health_os_version_performance.py +36 -0
  1012. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_autopilot_devices_summary.py +16 -0
  1013. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_baseline.py +121 -0
  1014. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_category.py +47 -0
  1015. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_cloud_identity_devices_summary.py +14 -0
  1016. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_cloud_management_devices_summary.py +16 -0
  1017. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_device_performance.py +127 -0
  1018. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_device_scores.py +65 -0
  1019. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_device_startup_history.py +101 -0
  1020. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_device_startup_process.py +36 -0
  1021. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_device_startup_process_performance.py +41 -0
  1022. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_insight.py +26 -0
  1023. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_insight_value.py +10 -0
  1024. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_metric.py +21 -0
  1025. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_metric_history.py +27 -0
  1026. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_model_scores.py +65 -0
  1027. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_overview.py +28 -0
  1028. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_score_history.py +17 -0
  1029. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_windows10_devices_summary.py +14 -0
  1030. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_work_from_anywhere_device.py +197 -0
  1031. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_work_from_anywhere_devices_summary.py +47 -0
  1032. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_work_from_anywhere_hardware_readiness_metric.py +66 -0
  1033. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_work_from_anywhere_metric.py +34 -0
  1034. office365/intune/devices/management/userexperienceanalytics/user_experience_analytics_work_from_anywhere_model_performance.py +65 -0
  1035. office365/intune/devices/management/virtualendpoint/virtual_endpoint.py +137 -0
  1036. office365/intune/devices/management/windows_autopilot_deployment_profile.py +106 -0
  1037. office365/intune/devices/management/windows_autopilot_deployment_profile_assignment.py +7 -0
  1038. office365/intune/devices/management/windows_autopilot_device_identity.py +97 -0
  1039. office365/intune/devices/management/windows_defender_scan_action_result.py +14 -0
  1040. office365/intune/devices/management/windows_device_account.py +14 -0
  1041. office365/intune/devices/management/windows_device_ad_account.py +15 -0
  1042. office365/intune/devices/management/windows_device_azure_ad_account.py +14 -0
  1043. office365/intune/devices/management/windows_information_protection_app.py +18 -0
  1044. office365/intune/devices/management/windows_information_protection_app_learning_summary.py +35 -0
  1045. office365/intune/devices/management/windows_information_protection_app_locker_file.py +31 -0
  1046. office365/intune/devices/management/windows_information_protection_data_recovery_certificate.py +18 -0
  1047. office365/intune/devices/management/windows_information_protection_desktop_app.py +16 -0
  1048. office365/intune/devices/management/windows_information_protection_ip_range_collection.py +17 -0
  1049. office365/intune/devices/management/windows_information_protection_network_learning_summary.py +21 -0
  1050. office365/intune/devices/management/windows_information_protection_pin_character_requirements.py +13 -0
  1051. office365/intune/devices/management/windows_information_protection_policy.py +76 -0
  1052. office365/intune/devices/management/windows_information_protection_proxied_domain_collection.py +19 -0
  1053. office365/intune/devices/management/windows_information_protection_resource_collection.py +16 -0
  1054. office365/intune/devices/management/windows_information_protection_store_app.py +10 -0
  1055. office365/intune/devices/management/windows_malware_overview.py +34 -1
  1056. office365/intune/devices/management/windows_protection_state.py +152 -0
  1057. office365/intune/devices/management/windowsmalware/malware_state_for_windows_device.py +58 -0
  1058. office365/intune/devices/management/windowsmalware/windows_device_malware_state.py +99 -0
  1059. office365/intune/devices/management/windowsmalware/windows_malware_category_count.py +22 -0
  1060. office365/intune/devices/management/windowsmalware/windows_malware_execution_state_count.py +20 -0
  1061. office365/intune/devices/management/windowsmalware/windows_malware_information.py +72 -0
  1062. office365/intune/devices/management/windowsmalware/windows_malware_name_count.py +18 -0
  1063. office365/intune/devices/management/windowsmalware/windows_malware_severity_count.py +21 -0
  1064. office365/intune/devices/management/windowsmalware/windows_malware_state_count.py +22 -0
  1065. office365/intune/devices/management_cached_report_configuration.py +7 -0
  1066. office365/intune/devices/management_exchange_connector.py +73 -0
  1067. office365/intune/devices/management_export_job.py +82 -0
  1068. office365/intune/devices/management_partner.py +84 -0
  1069. office365/intune/devices/management_troubleshooting_event.py +22 -0
  1070. office365/intune/organizations/branding.py +29 -0
  1071. office365/intune/organizations/branding_properties.py +187 -0
  1072. office365/intune/organizations/contact.py +132 -0
  1073. office365/intune/organizations/content_customization.py +9 -1
  1074. office365/intune/organizations/organization.py +125 -1
  1075. office365/intune/organizations/organizational_branding_localization.py +7 -0
  1076. office365/intune/print/air_print_settings.py +17 -0
  1077. office365/intune/print/archived_print_job.py +26 -0
  1078. office365/intune/print/certificate_signing_request.py +15 -0
  1079. office365/intune/print/connectors/connector.py +44 -0
  1080. office365/intune/print/document.py +37 -0
  1081. office365/intune/print/document_upload_properties.py +16 -0
  1082. office365/intune/print/job.py +91 -0
  1083. office365/intune/print/job_configuration.py +46 -0
  1084. office365/intune/print/job_status.py +22 -0
  1085. office365/intune/print/margin.py +17 -0
  1086. office365/intune/print/operation.py +28 -0
  1087. office365/intune/print/operation_status.py +18 -0
  1088. office365/intune/print/print.py +65 -0
  1089. office365/intune/print/printers/base.py +66 -0
  1090. office365/intune/print/printers/capabilities.py +82 -0
  1091. office365/intune/print/printers/create_operation.py +28 -0
  1092. office365/intune/print/printers/defaults.py +40 -0
  1093. office365/intune/print/printers/discovery_settings.py +15 -0
  1094. office365/intune/print/printers/location.py +31 -0
  1095. office365/intune/print/printers/printer.py +70 -0
  1096. office365/intune/print/printers/share_viewpoint.py +15 -0
  1097. office365/intune/print/printers/status.py +23 -0
  1098. office365/intune/print/services/endpoint.py +18 -0
  1099. office365/intune/print/settings.py +16 -0
  1100. office365/intune/print/shares/share.py +60 -0
  1101. office365/intune/print/task.py +47 -0
  1102. office365/intune/print/task_definition.py +38 -0
  1103. office365/intune/print/task_status.py +16 -0
  1104. office365/intune/print/task_trigger.py +32 -0
  1105. office365/intune/print/user_print.py +7 -0
  1106. office365/intune/servicecommunications/announcement_base.py +40 -0
  1107. office365/intune/servicecommunications/health/health.py +42 -0
  1108. office365/intune/servicecommunications/issues/issue.py +48 -1
  1109. office365/intune/servicecommunications/messages/update.py +105 -0
  1110. office365/intune/servicecommunications/service_health_issue_post.py +19 -0
  1111. office365/intune/servicecommunications/service_update_message_viewpoint.py +16 -0
  1112. office365/limits.py +66 -0
  1113. office365/migration/__init__.py +30 -3
  1114. office365/migration/adapters/__init__.py +44 -4
  1115. office365/migration/adapters/filesystem.py +4 -1
  1116. office365/migration/assessment/export.py +5 -5
  1117. office365/migration/assessment/issue.py +19 -0
  1118. office365/migration/assessment/report.py +11 -0
  1119. office365/migration/assessment/scanners/base.py +37 -49
  1120. office365/migration/base.py +135 -13
  1121. office365/migration/checkpoint.py +18 -17
  1122. office365/migration/delta.py +205 -0
  1123. office365/migration/fidelity.py +283 -0
  1124. office365/migration/job.py +172 -13
  1125. office365/migration/logging.py +373 -0
  1126. office365/migration/manifest.py +8 -3
  1127. office365/migration/map.py +84 -0
  1128. office365/migration/outlook/assessor.py +4 -4
  1129. office365/migration/package/__init__.py +82 -0
  1130. office365/migration/package/builder.py +669 -0
  1131. office365/migration/package/crypto.py +54 -0
  1132. office365/migration/package/manifest_xml.py +510 -0
  1133. office365/migration/package/staging.py +180 -0
  1134. office365/migration/report.py +7 -2
  1135. office365/migration/report_io.py +79 -0
  1136. office365/migration/runner.py +259 -23
  1137. office365/migration/server_job.py +205 -15
  1138. office365/migration/session.py +450 -50
  1139. office365/migration/settings.py +131 -0
  1140. office365/migration/sharepoint/__init__.py +150 -0
  1141. office365/migration/sharepoint/adapters.py +3010 -75
  1142. office365/migration/sharepoint/assessor.py +45 -9
  1143. office365/migration/sharepoint/branding.py +260 -0
  1144. office365/migration/sharepoint/handoff.py +252 -0
  1145. office365/migration/sharepoint/navigation.py +197 -0
  1146. office365/migration/sharepoint/options.py +57 -0
  1147. office365/migration/sharepoint/package_target.py +338 -0
  1148. office365/migration/sharepoint/pages.py +853 -0
  1149. office365/migration/sharepoint/registry.py +22 -0
  1150. office365/migration/sharepoint/resolvers.py +761 -0
  1151. office365/migration/sharepoint/scanners/__init__.py +29 -0
  1152. office365/migration/sharepoint/scanners/browser_file_handling.py +55 -0
  1153. office365/migration/sharepoint/scanners/checked_out_files.py +57 -0
  1154. office365/migration/sharepoint/scanners/file_versions.py +56 -0
  1155. office365/migration/sharepoint/scanners/files.py +5 -2
  1156. office365/migration/sharepoint/scanners/large_excel_files.py +56 -0
  1157. office365/migration/sharepoint/scanners/large_lists.py +58 -0
  1158. office365/migration/sharepoint/scanners/large_sites.py +4 -3
  1159. office365/migration/sharepoint/scanners/long_onedrive_urls.py +52 -0
  1160. office365/migration/sharepoint/scanners/lookup.py +38 -0
  1161. office365/migration/sharepoint/scanners/paths.py +9 -4
  1162. office365/migration/sharepoint/scanners/permissions.py +20 -2
  1163. office365/migration/sharepoint/scanners/smat.py +51 -0
  1164. office365/migration/sharepoint/scanners/summary.py +1 -0
  1165. office365/migration/sharepoint/scanners/thicket_folders.py +38 -0
  1166. office365/migration/sharepoint/scanners/unsupported_site_templates.py +90 -0
  1167. office365/migration/sharepoint/security.py +504 -0
  1168. office365/migration/sharepoint/site_scope.py +222 -0
  1169. office365/migration/sharepoint/site_settings.py +196 -0
  1170. office365/migration/sharepoint/site_verify.py +207 -0
  1171. office365/migration/sharepoint/structure.py +1426 -0
  1172. office365/migration/sharepoint/tenant_assessor.py +5 -3
  1173. office365/migration/sharepoint/transfer.py +4 -2
  1174. office365/migration/sharepoint/verify.py +186 -0
  1175. office365/migration/tasks.py +121 -0
  1176. office365/migration/teams/_extract.py +2 -1
  1177. office365/migration/teams/models.py +1 -0
  1178. office365/migration/throttling.py +215 -0
  1179. office365/migration/validators.py +249 -31
  1180. office365/onedrive/columns/definition.py +11 -0
  1181. office365/onedrive/contenttypes/content_type.py +24 -0
  1182. office365/onedrive/deleted.py +14 -0
  1183. office365/onedrive/driveitems/collection.py +30 -0
  1184. office365/onedrive/driveitems/copy_result.py +115 -0
  1185. office365/onedrive/driveitems/driveItem.py +413 -35
  1186. office365/onedrive/driveitems/retention_label_settings.py +1 -1
  1187. office365/onedrive/drives/drive.py +8 -9
  1188. office365/onedrive/filestorage/containers/container.py +157 -1
  1189. office365/onedrive/filestorage/containers/custom_property_value.py +2 -0
  1190. office365/onedrive/filestorage/containertypes/registration_settings.py +2 -0
  1191. office365/onedrive/filestorage/containertypes/settings.py +2 -0
  1192. office365/onedrive/filestorage/containertypes/settings_override.py +2 -0
  1193. office365/onedrive/internal/paths/children.py +7 -1
  1194. office365/onedrive/listitems/collection.py +34 -4
  1195. office365/onedrive/listitems/list_item.py +11 -0
  1196. office365/onedrive/lists/list.py +28 -1
  1197. office365/onedrive/operations/long_running.py +34 -2
  1198. office365/onedrive/operations/public_inner_error.py +7 -17
  1199. office365/onedrive/operations/rich_long_running.py +27 -1
  1200. office365/onedrive/permissions/permission.py +10 -0
  1201. office365/onedrive/sharepoint/migration/jobs/error_event.py +35 -1
  1202. office365/onedrive/shares/drive_item.py +2 -3
  1203. office365/onedrive/sitepages/collection.py +34 -4
  1204. office365/onedrive/sitepages/site_page.py +1 -1
  1205. office365/onedrive/sites/site.py +140 -1
  1206. office365/onedrive/sites/sites_with_root.py +21 -2
  1207. office365/onedrive/storage/settings.py +13 -0
  1208. office365/onedrive/termstore/groups/collection.py +24 -11
  1209. office365/onedrive/termstore/groups/group.py +26 -3
  1210. office365/onedrive/termstore/relation.py +8 -0
  1211. office365/onedrive/termstore/sets/collection.py +28 -20
  1212. office365/onedrive/termstore/sets/name.py +4 -0
  1213. office365/onedrive/termstore/sets/set.py +16 -3
  1214. office365/onedrive/termstore/store.py +27 -3
  1215. office365/onedrive/termstore/store_manager.py +42 -10
  1216. office365/onedrive/termstore/terms/collection.py +3 -10
  1217. office365/onedrive/termstore/terms/description.py +4 -0
  1218. office365/onedrive/termstore/terms/label.py +4 -0
  1219. office365/onedrive/termstore/terms/term.py +6 -1
  1220. office365/onedrive/wellknown_list_name.py +11 -0
  1221. office365/onedrive/workbooks/charts/area_format.py +27 -0
  1222. office365/onedrive/workbooks/charts/axis.py +79 -0
  1223. office365/onedrive/workbooks/charts/axis_format.py +32 -0
  1224. office365/onedrive/workbooks/charts/axis_title.py +38 -0
  1225. office365/onedrive/workbooks/charts/axis_title_format.py +22 -0
  1226. office365/onedrive/workbooks/charts/chart.py +44 -1
  1227. office365/onedrive/workbooks/charts/data_label_format.py +30 -0
  1228. office365/onedrive/workbooks/charts/data_labels.py +54 -1
  1229. office365/onedrive/workbooks/charts/fill.py +6 -0
  1230. office365/onedrive/workbooks/charts/font.py +38 -0
  1231. office365/onedrive/workbooks/charts/gridlines.py +33 -0
  1232. office365/onedrive/workbooks/charts/gridlines_format.py +24 -0
  1233. office365/onedrive/workbooks/charts/legend/format.py +27 -0
  1234. office365/onedrive/workbooks/charts/legend/legend.py +24 -1
  1235. office365/onedrive/workbooks/charts/line_format.py +16 -0
  1236. office365/onedrive/workbooks/charts/point.py +31 -0
  1237. office365/onedrive/workbooks/charts/point_format.py +22 -0
  1238. office365/onedrive/workbooks/charts/series/format.py +29 -0
  1239. office365/onedrive/workbooks/charts/series/series.py +13 -0
  1240. office365/onedrive/workbooks/charts/title.py +23 -0
  1241. office365/onedrive/workbooks/charts/title_format.py +27 -0
  1242. office365/onedrive/workbooks/comments/reply.py +18 -0
  1243. office365/onedrive/workbooks/filter.py +4 -0
  1244. office365/onedrive/workbooks/functions/functions.py +6 -0
  1245. office365/onedrive/workbooks/functions/result.py +13 -0
  1246. office365/onedrive/workbooks/names/named_item.py +27 -1
  1247. office365/onedrive/workbooks/operations/workbook.py +2 -1
  1248. office365/onedrive/workbooks/ranges/fill.py +6 -0
  1249. office365/onedrive/workbooks/ranges/format.py +6 -0
  1250. office365/onedrive/workbooks/ranges/format_protection.py +18 -0
  1251. office365/onedrive/workbooks/ranges/range.py +58 -1
  1252. office365/onedrive/workbooks/ranges/sort.py +6 -0
  1253. office365/onedrive/workbooks/ranges/view.py +67 -1
  1254. office365/onedrive/workbooks/tables/columns/column.py +18 -0
  1255. office365/onedrive/workbooks/tables/rows/row.py +6 -0
  1256. office365/onedrive/workbooks/tables/sort.py +22 -1
  1257. office365/onedrive/workbooks/tables/table.py +16 -0
  1258. office365/onedrive/workbooks/workbook.py +11 -0
  1259. office365/onedrive/workbooks/worksheets/protection.py +11 -0
  1260. office365/onedrive/workbooks/worksheets/worksheet.py +16 -0
  1261. office365/onenote/entity_base_model.py +13 -0
  1262. office365/onenote/notebooks/collection.py +38 -0
  1263. office365/onenote/notebooks/notebook.py +45 -4
  1264. office365/onenote/onenote.py +3 -3
  1265. office365/onenote/operations/onenote.py +24 -1
  1266. office365/onenote/pages/collection.py +36 -20
  1267. office365/onenote/pages/page.py +32 -0
  1268. office365/onenote/resources/resource.py +11 -0
  1269. office365/onenote/sectiongroups/section_group.py +20 -5
  1270. office365/onenote/sections/collection.py +47 -0
  1271. office365/onenote/sections/section.py +9 -5
  1272. office365/outlook/attachment_info.py +11 -0
  1273. office365/outlook/calendar/check_in_claim.py +32 -0
  1274. office365/outlook/calendar/events/event.py +29 -2
  1275. office365/outlook/calendar/place.py +56 -1
  1276. office365/outlook/calendar/place_collection.py +34 -0
  1277. office365/outlook/calendar/rooms/room.py +60 -1
  1278. office365/outlook/calendar/rooms/workspace.py +38 -0
  1279. office365/outlook/calendar/sharing_message.py +30 -0
  1280. office365/outlook/contacts/folders/collection.py +24 -13
  1281. office365/outlook/mail/attachments/attachment.py +11 -0
  1282. office365/outlook/mail/attachments/file.py +12 -1
  1283. office365/outlook/mail/attachments/type.py +7 -2
  1284. office365/outlook/mail/export_item_response.py +1 -1
  1285. office365/outlook/mail/folders/collection.py +38 -0
  1286. office365/outlook/mail/folders/folder.py +8 -3
  1287. office365/outlook/mail/messages/event_message.py +71 -0
  1288. office365/outlook/mail/messages/message.py +32 -13
  1289. office365/outlook/mail/post.py +118 -1
  1290. office365/outlook/people/person_type.py +2 -0
  1291. office365/outlook/people/profile_card_property.py +29 -0
  1292. office365/outlook/person.py +29 -1
  1293. office365/partners/billing/billed_reconciliation.py +3 -1
  1294. office365/partners/billing/billed_usage.py +3 -1
  1295. office365/partners/billing/billing.py +1 -1
  1296. office365/partners/billing/blob.py +15 -0
  1297. office365/partners/billing/export_success_operation.py +2 -1
  1298. office365/partners/billing/failed_operation.py +14 -1
  1299. office365/partners/billing/manifest.py +12 -1
  1300. office365/partners/billing/metrics.py +34 -0
  1301. office365/partners/billing/metrics_base.py +53 -0
  1302. office365/partners/billing/metrics_initial.py +17 -0
  1303. office365/partners/billing/metrics_recent.py +17 -0
  1304. office365/partners/billing/operation.py +35 -1
  1305. office365/partners/billing/reconciliation.py +40 -0
  1306. office365/partners/billing/running_operation.py +2 -1
  1307. office365/partners/billing/unbilled_reconciliation.py +3 -1
  1308. office365/partners/billing/unbilled_usage.py +3 -1
  1309. office365/partners/partnertenanttype.py +8 -12
  1310. office365/planner/applied_categories.py +10 -0
  1311. office365/planner/assigned_to_task_board_task_format.py +30 -0
  1312. office365/planner/assignment.py +31 -0
  1313. office365/planner/assignments.py +45 -1
  1314. office365/planner/bucket_task_board_task_format.py +16 -0
  1315. office365/planner/buckets/bucket.py +21 -8
  1316. office365/planner/buckets/collection.py +56 -15
  1317. office365/planner/category_descriptions.py +59 -0
  1318. office365/planner/entity.py +52 -0
  1319. office365/planner/external_reference.py +20 -0
  1320. office365/planner/internal/paths/collections.py +27 -0
  1321. office365/planner/order_hints_by_assignee.py +10 -0
  1322. office365/planner/planner.py +2 -2
  1323. office365/planner/plans/container.py +4 -0
  1324. office365/planner/plans/details.py +6 -2
  1325. office365/planner/plans/plan.py +36 -25
  1326. office365/planner/progress_task_board_task_format.py +16 -0
  1327. office365/planner/tasks/check_list_item.py +28 -1
  1328. office365/planner/tasks/check_list_items.py +46 -9
  1329. office365/planner/tasks/collection.py +67 -32
  1330. office365/planner/tasks/task.py +178 -24
  1331. office365/planner/tasks/task_details.py +54 -5
  1332. office365/planner/user.py +8 -6
  1333. office365/reports/internal/queries/create_report_query.py +3 -24
  1334. office365/reports/partners.py +11 -0
  1335. office365/reports/report.py +4 -0
  1336. office365/reports/report_export.py +197 -0
  1337. office365/reports/report_result.py +55 -0
  1338. office365/reports/root.py +90 -45
  1339. office365/reports/security/root.py +12 -6
  1340. office365/runtime/auth/authentication_context.py +95 -19
  1341. office365/runtime/auth/certificate.py +105 -0
  1342. office365/runtime/auth/entra/authentication_context.py +130 -9
  1343. office365/runtime/client_object.py +163 -5
  1344. office365/runtime/client_object_collection.py +411 -241
  1345. office365/runtime/client_request.py +388 -11
  1346. office365/runtime/client_request_exception.py +191 -41
  1347. office365/runtime/client_result.py +80 -2
  1348. office365/runtime/client_runtime_context.py +739 -31
  1349. office365/runtime/client_value.py +29 -10
  1350. office365/runtime/client_value_collection.py +30 -15
  1351. office365/runtime/converters/csv_writer.py +10 -4
  1352. office365/runtime/converters/dataframe.py +84 -4
  1353. office365/runtime/converters/json_file.py +12 -3
  1354. office365/runtime/converters/parquet.py +67 -0
  1355. office365/runtime/converters/records.py +31 -12
  1356. office365/runtime/converters/registry.py +185 -0
  1357. office365/runtime/converters/scalars.py +58 -0
  1358. office365/runtime/converters/sql.py +69 -0
  1359. office365/runtime/converters/streamers.py +105 -0
  1360. office365/runtime/converters/streams.py +42 -0
  1361. office365/runtime/converters/upsert.py +101 -0
  1362. office365/runtime/converters/value.py +31 -4
  1363. office365/runtime/display.py +232 -0
  1364. office365/runtime/exceptions.py +166 -0
  1365. office365/runtime/http/prefer.py +147 -0
  1366. office365/runtime/http/request_options.py +10 -3
  1367. office365/runtime/http/throttling.py +389 -57
  1368. office365/runtime/imports.py +697 -0
  1369. office365/runtime/limits.py +455 -0
  1370. office365/runtime/lro.py +751 -0
  1371. office365/runtime/odata/batch_util.py +33 -1
  1372. office365/runtime/odata/literals.py +49 -0
  1373. office365/runtime/odata/request.py +20 -6
  1374. office365/runtime/odata/type.py +11 -4
  1375. office365/runtime/odata/v3/batch_request.py +175 -25
  1376. office365/runtime/odata/v4/batch_request.py +164 -18
  1377. office365/runtime/odata/v4/upload_session_request.py +18 -0
  1378. office365/runtime/operations.py +29 -0
  1379. office365/runtime/parallel.py +12 -14
  1380. office365/runtime/paths/alternate_key.py +44 -0
  1381. office365/runtime/paths/appid.py +8 -8
  1382. office365/runtime/paths/builder.py +11 -5
  1383. office365/runtime/paths/v4/entity.py +2 -2
  1384. office365/runtime/persistence.py +71 -0
  1385. office365/runtime/pollable.py +234 -0
  1386. office365/runtime/progress.py +52 -0
  1387. office365/runtime/queries/batch.py +31 -6
  1388. office365/runtime/queries/client_query.py +27 -1
  1389. office365/runtime/queries/deferred.py +7 -0
  1390. office365/runtime/queries/get_or_create.py +125 -0
  1391. office365/runtime/queries/upsert_entity.py +103 -0
  1392. office365/runtime/query_capabilities.py +333 -0
  1393. office365/runtime/record_collection.py +615 -0
  1394. office365/runtime/respond_async.py +132 -0
  1395. office365/runtime/retry.py +200 -21
  1396. office365/runtime/transport/base.py +165 -4
  1397. office365/runtime/transport/httpx_transport.py +263 -0
  1398. office365/runtime/transport/offload.py +156 -0
  1399. office365/runtime/transport/requests_transport.py +166 -17
  1400. office365/runtime/transport/throttled_transport.py +90 -0
  1401. office365/runtime/verification.py +72 -0
  1402. office365/search/acronyms/acronym.py +19 -0
  1403. office365/search/aggregation_option.py +12 -0
  1404. office365/search/alteration_response.py +18 -0
  1405. office365/search/altered_query_token.py +16 -0
  1406. office365/search/answers/keyword.py +17 -0
  1407. office365/search/answers/variant.py +19 -0
  1408. office365/search/bookmarks/bookmark.py +21 -1
  1409. office365/search/bucket.py +4 -0
  1410. office365/search/bucket_aggregation_definition.py +23 -0
  1411. office365/search/bucket_aggregation_range.py +15 -0
  1412. office365/search/collapse_property.py +16 -0
  1413. office365/search/connection_item.py +14 -0
  1414. office365/search/entity_type.py +1 -1
  1415. office365/search/external/connection.py +88 -0
  1416. office365/search/external/item.py +29 -0
  1417. office365/search/external/item_configuration.py +18 -0
  1418. office365/search/external/search_settings.py +11 -1
  1419. office365/search/hits/container.py +4 -0
  1420. office365/search/hits/hit.py +10 -0
  1421. office365/search/identity.py +16 -0
  1422. office365/search/identity_set.py +8 -1
  1423. office365/search/qnas/qna.py +21 -1
  1424. office365/search/query.py +4 -0
  1425. office365/search/recommended_action.py +16 -0
  1426. office365/search/request.py +17 -0
  1427. office365/search/response.py +10 -0
  1428. office365/search/result_template.py +16 -0
  1429. office365/search/result_template_dictionary.py +10 -0
  1430. office365/search/result_template_option.py +14 -0
  1431. office365/search/retrieval_extract.py +15 -0
  1432. office365/search/retrieval_hit.py +27 -0
  1433. office365/search/retrieval_response.py +18 -0
  1434. office365/search/search_alteration.py +21 -0
  1435. office365/search/search_alteration_options.py +15 -0
  1436. office365/search/search_resource_metadata_dictionary.py +10 -0
  1437. office365/search/search_result.py +14 -0
  1438. office365/search/sharepoint_onedrive_options.py +7 -0
  1439. office365/search/sort_property.py +4 -0
  1440. office365/security/account.py +24 -0
  1441. office365/security/account_target_content.py +17 -0
  1442. office365/security/activity_metadata.py +15 -0
  1443. office365/security/address_book_account_target_content.py +15 -0
  1444. office365/security/ai_agent_evidence.py +19 -0
  1445. office365/security/alerts/alert.py +459 -0
  1446. office365/security/alerts/blob_container_evidence.py +17 -0
  1447. office365/security/alerts/blob_evidence.py +21 -0
  1448. office365/security/alerts/collection.py +49 -0
  1449. office365/security/alerts/detection.py +16 -0
  1450. office365/security/alerts/evidence.py +28 -0
  1451. office365/security/alerts/file_security_state.py +23 -0
  1452. office365/security/alerts/history_state.py +31 -0
  1453. office365/security/alerts/malware_evidence.py +22 -0
  1454. office365/security/alerts/process_evidence.py +27 -0
  1455. office365/security/alerts/sas_token_evidence.py +26 -0
  1456. office365/security/alerts/trigger.py +16 -0
  1457. office365/security/analyzed_message_evidence.py +34 -0
  1458. office365/security/article.py +75 -0
  1459. office365/security/assigned_training_info.py +16 -0
  1460. office365/security/attacksimulations/automation.py +90 -0
  1461. office365/security/attacksimulations/automation_run.py +43 -0
  1462. office365/security/attacksimulations/event.py +22 -0
  1463. office365/security/attacksimulations/landing_page.py +105 -0
  1464. office365/security/attacksimulations/landing_page_detail.py +26 -0
  1465. office365/security/attacksimulations/login_page.py +83 -0
  1466. office365/security/attacksimulations/operations/operation.py +37 -0
  1467. office365/security/attacksimulations/payload.py +192 -0
  1468. office365/security/attacksimulations/repeat_offender.py +21 -0
  1469. office365/security/attacksimulations/reports/overview.py +30 -0
  1470. office365/security/attacksimulations/reports/report.py +29 -0
  1471. office365/security/attacksimulations/root.py +124 -0
  1472. office365/security/attacksimulations/simulation.py +220 -0
  1473. office365/security/attacksimulations/training_user_coverage.py +22 -0
  1474. office365/security/attacksimulations/user.py +20 -0
  1475. office365/security/attacksimulations/user_coverage.py +26 -0
  1476. office365/security/attacksimulations/users/details.py +48 -0
  1477. office365/security/attribute_definition.py +37 -0
  1478. office365/security/attribute_mapping.py +11 -0
  1479. office365/security/attribute_mapping_source.py +25 -0
  1480. office365/security/audit/audit_data.py +15 -0
  1481. office365/security/audit/core_root.py +26 -0
  1482. office365/security/audit/log_query.py +114 -0
  1483. office365/security/audit/log_record.py +84 -0
  1484. office365/security/audit/whois_record.py +22 -0
  1485. office365/security/average_comparative_score.py +15 -0
  1486. office365/security/base_end_user_notification.py +20 -0
  1487. office365/security/cases/case.py +48 -0
  1488. office365/security/cases/ediscovery.py +136 -0
  1489. office365/security/cases/operation.py +67 -0
  1490. office365/security/cases/root.py +21 -0
  1491. office365/security/category_template.py +30 -0
  1492. office365/security/certification_control.py +15 -0
  1493. office365/security/cloud_app_security_state.py +16 -0
  1494. office365/security/cloud_application_evidence.py +20 -0
  1495. office365/security/cloud_clipboard_item.py +44 -0
  1496. office365/security/cloud_clipboard_item_payload.py +15 -0
  1497. office365/security/cloud_clipboard_root.py +28 -0
  1498. office365/security/cloud_flare_rule_model.py +16 -0
  1499. office365/security/cloud_flare_ruleset_model.py +16 -0
  1500. office365/security/cloud_flare_verified_details_model.py +25 -0
  1501. office365/security/cloud_flare_web_application_firewall_provider.py +21 -0
  1502. office365/security/cloud_logon_session_evidence.py +24 -0
  1503. office365/security/cloud_pc_audit_event.py +105 -0
  1504. office365/security/cloud_pc_device_image.py +95 -0
  1505. office365/security/cloud_pc_gallery_image.py +71 -0
  1506. office365/security/cloud_pc_on_premises_connection.py +130 -0
  1507. office365/security/cloud_pc_provisioning_policy.py +156 -0
  1508. office365/security/cloud_pc_provisioning_policy_assignment.py +38 -0
  1509. office365/security/cloud_pc_report.py +9 -0
  1510. office365/security/cloud_pc_service_plan.py +31 -0
  1511. office365/security/cloud_pc_user_setting.py +70 -0
  1512. office365/security/cloud_pc_user_setting_assignment.py +31 -0
  1513. office365/security/cloud_video_interop_info.py +16 -0
  1514. office365/security/coachmark_location.py +18 -0
  1515. office365/security/coachmark_location_type.py +17 -0
  1516. office365/security/collaboration/analyzed_email.py +288 -0
  1517. office365/security/collaboration/analyzed_email_attachment.py +25 -0
  1518. office365/security/collaboration/analyzed_email_delivery_detail.py +21 -0
  1519. office365/security/collaboration/analyzed_email_url.py +21 -0
  1520. office365/security/collaboration/collaboration_root.py +22 -0
  1521. office365/security/compromise_indicator.py +17 -0
  1522. office365/security/container_evidence.py +28 -0
  1523. office365/security/container_image_evidence.py +17 -0
  1524. office365/security/control_score.py +17 -0
  1525. office365/security/custom_training_setting.py +24 -0
  1526. office365/security/cvss_summary.py +18 -0
  1527. office365/security/data_source_container.py +44 -0
  1528. office365/security/datasecurity/classifcation_error_base.py +18 -0
  1529. office365/security/datasecurity/classification_error.py +20 -0
  1530. office365/security/datasecurity/compute_rights_and_inheritance_result.py +25 -0
  1531. office365/security/datasecurity/governance.py +42 -0
  1532. office365/security/datasecurity/label_content_right.py +44 -0
  1533. office365/security/datasecurity/policy_scope_base.py +26 -0
  1534. office365/security/datasecurity/policy_tenant_scope.py +15 -0
  1535. office365/security/datasecurity/policy_tip_action.py +16 -0
  1536. office365/security/datasecurity/process_content_batch_request.py +17 -0
  1537. office365/security/datasecurity/process_content_request.py +33 -0
  1538. office365/security/datasecurity/process_content_response.py +24 -0
  1539. office365/security/datasecurity/process_content_responses.py +16 -0
  1540. office365/security/datasecurity/process_file_metadata.py +16 -0
  1541. office365/security/datasecurity/sensitivity_label.py +117 -0
  1542. office365/security/datasecurity/tenant_protection_scope_container.py +9 -0
  1543. office365/security/datasecurity/usage_rights_included.py +31 -0
  1544. office365/security/detonation_details.py +34 -0
  1545. office365/security/device_evidence.py +50 -0
  1546. office365/security/dns_evidence.py +19 -0
  1547. office365/security/ediscovery/case_member.py +31 -0
  1548. office365/security/ediscovery/custodian.py +76 -0
  1549. office365/security/ediscovery/ediscovery_case_settings.py +57 -0
  1550. office365/security/ediscovery/ediscovery_estimate_operation.py +66 -0
  1551. office365/security/ediscovery/ediscovery_export_operation.py +64 -0
  1552. office365/security/ediscovery/ediscovery_index_operation.py +8 -0
  1553. office365/security/ediscovery/ediscovery_review_tag.py +34 -0
  1554. office365/security/ediscovery/noncustodial_data_source.py +37 -0
  1555. office365/security/ediscovery/operations/add_to_review_set.py +64 -0
  1556. office365/security/ediscovery/operations/hold.py +8 -0
  1557. office365/security/ediscovery/operations/hold_policy_sync.py +23 -0
  1558. office365/security/ediscovery/operations/purge_data.py +23 -0
  1559. office365/security/ediscovery/operations/search_export.py +83 -0
  1560. office365/security/ediscovery/operations/tag.py +8 -0
  1561. office365/security/ediscovery/review_set.py +22 -0
  1562. office365/security/ediscovery/review_set_query.py +9 -0
  1563. office365/security/ediscovery/search.py +81 -0
  1564. office365/security/email_payload_detail.py +17 -0
  1565. office365/security/end_user_notification.py +110 -0
  1566. office365/security/end_user_notification_detail.py +46 -0
  1567. office365/security/end_user_notification_setting.py +25 -0
  1568. office365/security/evaluation_outcome.py +13 -0
  1569. office365/security/event_propagation_result.py +18 -0
  1570. office365/security/event_query.py +17 -0
  1571. office365/security/expression_input_object.py +20 -0
  1572. office365/security/file_evidence.py +18 -0
  1573. office365/security/file_hash.py +21 -0
  1574. office365/security/file_hash_evidence.py +16 -0
  1575. office365/security/file_plan_applied_category.py +15 -0
  1576. office365/security/filter.py +22 -0
  1577. office365/security/filter_clause.py +17 -0
  1578. office365/security/filter_group.py +17 -0
  1579. office365/security/formatted_content.py +16 -0
  1580. office365/security/google_cloud_resource_evidence.py +21 -0
  1581. office365/security/health_issue.py +81 -0
  1582. office365/security/host_security_state.py +22 -0
  1583. office365/security/host_ssl_certificate_port.py +17 -0
  1584. office365/security/hunting_query_results.py +24 -0
  1585. office365/security/hyperlink.py +15 -0
  1586. office365/security/identity_accounts.py +47 -0
  1587. office365/security/identity_provider.py +14 -0
  1588. office365/security/incidents/incident.py +148 -0
  1589. office365/security/include_all_account_target_content.py +10 -0
  1590. office365/security/indicator.py +28 -0
  1591. office365/security/intelligence_profile_country_or_region_of_origin.py +15 -0
  1592. office365/security/investigation_security_state.py +15 -0
  1593. office365/security/invoke_action_result.py +24 -0
  1594. office365/security/io_t_device_evidence.py +46 -0
  1595. office365/security/ip_address.py +36 -0
  1596. office365/security/ip_evidence.py +19 -0
  1597. office365/security/kubernetes_cluster_evidence.py +20 -0
  1598. office365/security/kubernetes_controller_evidence.py +19 -0
  1599. office365/security/kubernetes_namespace_evidence.py +18 -0
  1600. office365/security/kubernetes_pod_evidence.py +38 -0
  1601. office365/security/kubernetes_secret_evidence.py +17 -0
  1602. office365/security/kubernetes_service_account_evidence.py +16 -0
  1603. office365/security/kubernetes_service_evidence.py +29 -0
  1604. office365/security/kubernetes_service_port.py +20 -0
  1605. office365/security/labels/retention/collection.py +68 -0
  1606. office365/security/labels/retention/duration_in_days.py +16 -0
  1607. office365/security/labels/retention/fileplan_descriptor.py +104 -0
  1608. office365/security/labels/retention/label.py +158 -0
  1609. office365/security/labels/root.py +83 -0
  1610. office365/security/mailbox_configuration_evidence.py +24 -0
  1611. office365/security/mailbox_evidence.py +18 -0
  1612. office365/security/malware_state.py +18 -0
  1613. office365/security/message_security_state.py +23 -0
  1614. office365/security/microsoft_custom_training_setting.py +26 -0
  1615. office365/security/microsoft_managed_training_setting.py +19 -0
  1616. office365/security/microsoft_training_assignment_mapping.py +26 -0
  1617. office365/security/monitor_mode.py +12 -0
  1618. office365/security/monitor_run_status.py +14 -0
  1619. office365/security/monitor_status.py +13 -0
  1620. office365/security/network_connection.py +39 -0
  1621. office365/security/network_connection_evidence.py +21 -0
  1622. office365/security/nic_evidence.py +18 -0
  1623. office365/security/no_training_notification_setting.py +15 -0
  1624. office365/security/no_training_setting.py +10 -0
  1625. office365/security/object_definition.py +25 -0
  1626. office365/security/object_mapping.py +33 -0
  1627. office365/security/parse_expression_response.py +22 -0
  1628. office365/security/passive_dns_record.py +47 -0
  1629. office365/security/payload_coachmark.py +21 -0
  1630. office365/security/payload_detail.py +20 -0
  1631. office365/security/positive_reinforcement_notification.py +17 -0
  1632. office365/security/process.py +28 -0
  1633. office365/security/processing_error.py +15 -0
  1634. office365/security/registry_key_state.py +26 -0
  1635. office365/security/retention_event.py +98 -0
  1636. office365/security/retention_event_status.py +18 -0
  1637. office365/security/scorecontrol/profile.py +135 -0
  1638. office365/security/search/data_source.py +34 -0
  1639. office365/security/securescores/control_state_update.py +19 -0
  1640. office365/security/securescores/secure_score.py +85 -0
  1641. office365/security/security.py +208 -0
  1642. office365/security/security_resource.py +18 -0
  1643. office365/security/security_vendor_information.py +17 -0
  1644. office365/security/sensitivity_label_info.py +18 -0
  1645. office365/security/sensor.py +84 -0
  1646. office365/security/sensor_candidate_activation_configuration.py +25 -0
  1647. office365/security/sensor_settings.py +20 -0
  1648. office365/security/service_principal_evidence.py +21 -0
  1649. office365/security/settings_container.py +19 -0
  1650. office365/security/simulation_event.py +15 -0
  1651. office365/security/simulation_events_content.py +19 -0
  1652. office365/security/simulation_notification.py +17 -0
  1653. office365/security/ssl_certificate.py +78 -0
  1654. office365/security/ssl_certificate_entity.py +24 -0
  1655. office365/security/string_key_attribute_mapping_source_value_pair.py +19 -0
  1656. office365/security/subdomain.py +26 -0
  1657. office365/security/subjectrightsrequests/authored_note.py +35 -0
  1658. office365/security/subjectrightsrequests/request.py +255 -0
  1659. office365/security/teams_message_evidence.py +52 -0
  1660. office365/security/threatintelligence/host.py +138 -0
  1661. office365/security/threatintelligence/host_component.py +46 -0
  1662. office365/security/threatintelligence/host_cookie.py +41 -0
  1663. office365/security/threatintelligence/host_logon_session_evidence.py +21 -0
  1664. office365/security/threatintelligence/host_pair.py +41 -0
  1665. office365/security/threatintelligence/host_port.py +106 -0
  1666. office365/security/threatintelligence/host_port_component.py +19 -0
  1667. office365/security/threatintelligence/host_reputation.py +43 -0
  1668. office365/security/threatintelligence/host_reputation_rule.py +21 -0
  1669. office365/security/threatintelligence/host_ssl_certificate.py +56 -0
  1670. office365/security/threatintelligence/host_tracker.py +41 -0
  1671. office365/security/threatintelligence/hosts/__init__.py +0 -0
  1672. office365/security/threatintelligence/profile.py +114 -0
  1673. office365/security/threatintelligence/threat_intelligence.py +193 -0
  1674. office365/security/threatintelligence/whoisrecords/__init__.py +0 -0
  1675. office365/security/timeline_event.py +25 -0
  1676. office365/security/training.py +123 -0
  1677. office365/security/training_language_detail.py +64 -0
  1678. office365/security/training_notification_setting.py +21 -0
  1679. office365/security/training_reminder_notification.py +17 -0
  1680. office365/security/training_setting.py +17 -0
  1681. office365/security/triggers/__init__.py +0 -0
  1682. office365/security/triggers/root.py +30 -0
  1683. office365/security/triggertypes/__init__.py +0 -0
  1684. office365/security/triggertypes/collection.py +9 -0
  1685. office365/security/triggertypes/root.py +24 -0
  1686. office365/security/unified_group_source.py +22 -0
  1687. office365/security/uri_click_security_state.py +20 -0
  1688. office365/security/user.py +21 -0
  1689. office365/security/user_account.py +27 -0
  1690. office365/security/user_evidence.py +17 -0
  1691. office365/security/user_security_state.py +33 -0
  1692. office365/security/user_simulation_event_info.py +21 -0
  1693. office365/security/user_source.py +27 -0
  1694. office365/security/user_training_content_event_info.py +19 -0
  1695. office365/security/user_training_event_info.py +22 -0
  1696. office365/security/user_training_status_info.py +19 -0
  1697. office365/security/vm_metadata.py +19 -0
  1698. office365/security/vulnerability.py +134 -0
  1699. office365/security/vulnerability_state.py +16 -0
  1700. office365/security/whois_base_record.py +127 -0
  1701. office365/security/whois_contact.py +20 -0
  1702. office365/security/whois_nameserver.py +21 -0
  1703. office365/sharepoint/activities/entity.py +9 -0
  1704. office365/sharepoint/activities/logger.py +118 -8
  1705. office365/sharepoint/administration/analytics/usage_service.py +15 -7
  1706. office365/sharepoint/administration/sitemove/service.py +857 -5
  1707. office365/sharepoint/administration/sitemove/systemsitelockexpres.py +8 -0
  1708. office365/sharepoint/administration/spfarm.py +8 -0
  1709. office365/sharepoint/administration/spwebapplication.py +23 -1
  1710. office365/sharepoint/alerts/alert.py +89 -0
  1711. office365/sharepoint/approvals/approvals.py +262 -1
  1712. office365/sharepoint/apps/access_requests.py +69 -0
  1713. office365/sharepoint/apps/app_collection.py +25 -0
  1714. office365/sharepoint/apps/appsitecontextutility.py +23 -1
  1715. office365/sharepoint/apps/apptileproperties.py +63 -1
  1716. office365/sharepoint/apps/catalog.py +18 -1
  1717. office365/sharepoint/apps/instance.py +87 -1
  1718. office365/sharepoint/apps/launcher.py +16 -0
  1719. office365/sharepoint/apps/management/principal_info.py +19 -0
  1720. office365/sharepoint/attachments/collection.py +20 -3
  1721. office365/sharepoint/audit/audit.py +5 -0
  1722. office365/sharepoint/authentication/auth_file_detonation_request_response.py +15 -0
  1723. office365/sharepoint/authpolicy/events/event.py +20 -0
  1724. office365/sharepoint/authpolicy/tenant/compliancereport.py +5 -0
  1725. office365/sharepoint/authpolicy/tenant/compliancereportentitydata.py +12 -0
  1726. office365/sharepoint/automations/automations.py +682 -1
  1727. office365/sharepoint/brandcenter/brand_center.py +277 -0
  1728. office365/sharepoint/businessdata/app_bdc_catalog.py +135 -0
  1729. office365/sharepoint/businessdata/entityfieldvaluedictionary.py +65 -0
  1730. office365/sharepoint/businessdata/entityidentifier.py +23 -0
  1731. office365/sharepoint/businessdata/entityinstance.py +52 -0
  1732. office365/sharepoint/businessdata/entityview.py +31 -0
  1733. office365/sharepoint/businessdata/externalsubscriptionstore.py +9 -0
  1734. office365/sharepoint/businessdata/infrastructure/securestore/connection_settings.py +42 -0
  1735. office365/sharepoint/businessdata/runtime/subscription.py +16 -0
  1736. office365/sharepoint/businessdata/typedescriptor.py +37 -0
  1737. office365/sharepoint/changes/alert.py +8 -0
  1738. office365/sharepoint/changes/app_consent_principal.py +9 -0
  1739. office365/sharepoint/changes/change.py +7 -0
  1740. office365/sharepoint/changes/content_type.py +8 -0
  1741. office365/sharepoint/changes/field.py +8 -0
  1742. office365/sharepoint/changes/folder.py +7 -0
  1743. office365/sharepoint/changes/item.py +53 -0
  1744. office365/sharepoint/changes/list.py +23 -0
  1745. office365/sharepoint/client_context.py +329 -35
  1746. office365/sharepoint/clientsidecomponent/hostedapps/add_response.py +19 -0
  1747. office365/sharepoint/clientsidecomponent/hostedapps/app.py +21 -0
  1748. office365/sharepoint/clientsidecomponent/hostedapps/manager.py +16 -0
  1749. office365/sharepoint/comments/collection.py +1 -1
  1750. office365/sharepoint/comments/comment.py +103 -2
  1751. office365/sharepoint/compliance/sensitivitylabels/collection.py +33 -1
  1752. office365/sharepoint/content_solution.py +18 -0
  1753. office365/sharepoint/contentcenter/machinelearning/enabled.py +37 -0
  1754. office365/sharepoint/contentcenter/machinelearning/hub.py +57 -8
  1755. office365/sharepoint/contentcenter/machinelearning/models/entity_data.py +135 -0
  1756. office365/sharepoint/contentcenter/machinelearning/models/model.py +16 -21
  1757. office365/sharepoint/contentcenter/machinelearning/publications/publication.py +6 -8
  1758. office365/sharepoint/contentcenter/machinelearning/samples/entity_data.py +14 -0
  1759. office365/sharepoint/contentcenter/machinelearning/samples/sample.py +6 -13
  1760. office365/sharepoint/contentcenter/machinelearning/workitementitydata.py +7 -0
  1761. office365/sharepoint/contentcenter/machinelearning/workitems/item.py +11 -79
  1762. office365/sharepoint/contentcenter/sp_machine_learning_column_autofill_prompt_suggestion_data.py +25 -0
  1763. office365/sharepoint/contentcenter/sp_machine_learning_column_autofill_prompt_suggestion_result.py +16 -0
  1764. office365/sharepoint/contentcenter/sp_machine_learning_publications_result.py +38 -0
  1765. office365/sharepoint/contentcenter/syntex_models_landing_info.py +24 -0
  1766. office365/sharepoint/contentcenter/template_api.py +195 -0
  1767. office365/sharepoint/contentsolution/template_api.py +148 -0
  1768. office365/sharepoint/contenttypes/collection.py +79 -20
  1769. office365/sharepoint/contenttypes/content_type.py +146 -5
  1770. office365/sharepoint/contenttypes/content_type_id.py +4 -0
  1771. office365/sharepoint/contenttypes/fieldlinks/collection.py +1 -2
  1772. office365/sharepoint/contenttypes/fieldlinks/field_link.py +20 -2
  1773. office365/sharepoint/convergence/addnoliveblobsinodcservicestateapi.py +9 -0
  1774. office365/sharepoint/convergence/consumer_permissions.py +15 -0
  1775. office365/sharepoint/convergence/migration_complete_state_api.py +25 -0
  1776. office365/sharepoint/convergence/odcmetadatacleanedupapi.py +9 -0
  1777. office365/sharepoint/directory/conditional_access_policy.py +5 -0
  1778. office365/sharepoint/directory/group_and_user_status.py +9 -0
  1779. office365/sharepoint/directory/groups/group.py +203 -6
  1780. office365/sharepoint/directory/link.py +20 -0
  1781. office365/sharepoint/directory/members_info.py +15 -0
  1782. office365/sharepoint/directory/multi_conditional_access_policy.py +5 -0
  1783. office365/sharepoint/directory/my_groups_result.py +14 -0
  1784. office365/sharepoint/directory/named_location_policy.py +15 -0
  1785. office365/sharepoint/directory/provider/provider.py +141 -0
  1786. office365/sharepoint/directory/session.py +69 -0
  1787. office365/sharepoint/directory/tenant.py +37 -0
  1788. office365/sharepoint/directory/users/user.py +343 -1
  1789. office365/sharepoint/document_location.py +14 -0
  1790. office365/sharepoint/documentmanagement/document_id.py +12 -0
  1791. office365/sharepoint/documentmanagement/document_set.py +4 -0
  1792. office365/sharepoint/dynamiccontent/updateservice.py +207 -1
  1793. office365/sharepoint/edgeworth_settings_apis.py +7 -0
  1794. office365/sharepoint/engage_distribution_info.py +17 -0
  1795. office365/sharepoint/entity.py +105 -6
  1796. office365/sharepoint/entity_collection.py +88 -3
  1797. office365/sharepoint/esign/digitallegacy.py +371 -1
  1798. office365/sharepoint/eventreceivers/definition.py +26 -0
  1799. office365/sharepoint/exceptions.py +194 -0
  1800. office365/sharepoint/features/definitions/definition.py +8 -0
  1801. office365/sharepoint/fields/builtin_field_id.py +45 -34
  1802. office365/sharepoint/fields/builtin_field_name.py +123 -0
  1803. office365/sharepoint/fields/calculated.py +22 -0
  1804. office365/sharepoint/fields/choice.py +9 -0
  1805. office365/sharepoint/fields/coercion.py +131 -0
  1806. office365/sharepoint/fields/collection.py +112 -41
  1807. office365/sharepoint/fields/field.py +126 -1
  1808. office365/sharepoint/fields/lookup.py +23 -0
  1809. office365/sharepoint/fields/multi_choice.py +7 -0
  1810. office365/sharepoint/fields/multi_line_text.py +12 -0
  1811. office365/sharepoint/fields/name.py +46 -2
  1812. office365/sharepoint/fields/number.py +27 -0
  1813. office365/sharepoint/fields/rating_scale.py +27 -0
  1814. office365/sharepoint/fields/user.py +12 -0
  1815. office365/sharepoint/files/checked_out_file.py +15 -0
  1816. office365/sharepoint/files/collection.py +276 -39
  1817. office365/sharepoint/files/download_operation.py +466 -0
  1818. office365/sharepoint/files/file.py +699 -25
  1819. office365/sharepoint/files/file_url_virus_status_update.py +9 -0
  1820. office365/sharepoint/files/publish/status.py +43 -0
  1821. office365/sharepoint/files/recent_file_collection.py +41 -0
  1822. office365/sharepoint/files/versions/collection.py +1 -1
  1823. office365/sharepoint/files/versions/event.py +13 -0
  1824. office365/sharepoint/files/versions/version.py +38 -13
  1825. office365/sharepoint/flows/synchronization_result.py +13 -1
  1826. office365/sharepoint/folders/collection.py +4 -0
  1827. office365/sharepoint/folders/coloring.py +29 -0
  1828. office365/sharepoint/folders/folder.py +264 -25
  1829. office365/sharepoint/fontpackages/font_package.py +69 -0
  1830. office365/sharepoint/fontpackages/oob_settings.py +47 -0
  1831. office365/sharepoint/forms/form.py +8 -0
  1832. office365/sharepoint/glutamate_controller.py +44 -0
  1833. office365/sharepoint/htmlpages/html_page.py +21 -0
  1834. office365/sharepoint/htmlpages/html_page_service.py +19 -0
  1835. office365/sharepoint/ir/migration.py +9 -0
  1836. office365/sharepoint/item_reference.py +17 -0
  1837. office365/sharepoint/largeoperation/operation.py +26 -1
  1838. office365/sharepoint/likes/user_entity.py +7 -0
  1839. office365/sharepoint/list_creation_information.py +18 -0
  1840. office365/sharepoint/listhome/favorite_lists.py +130 -0
  1841. office365/sharepoint/listhome/favoritelistssubstrate.py +106 -1
  1842. office365/sharepoint/listhome/item2.py +7 -0
  1843. office365/sharepoint/listhome/itemcollection.py +99 -1
  1844. office365/sharepoint/listhome/nucleus.py +15 -1
  1845. office365/sharepoint/listhome/pinneditems.py +127 -1
  1846. office365/sharepoint/listitems/caml/__init__.py +31 -0
  1847. office365/sharepoint/listitems/caml/builder.py +129 -0
  1848. office365/sharepoint/listitems/caml/expressions.py +424 -0
  1849. office365/sharepoint/listitems/caml/fields.py +68 -0
  1850. office365/sharepoint/listitems/caml/guard.py +63 -0
  1851. office365/sharepoint/listitems/caml/query.py +71 -2
  1852. office365/sharepoint/listitems/caml/values.py +113 -0
  1853. office365/sharepoint/listitems/collection.py +48 -19
  1854. office365/sharepoint/listitems/favoriteitemcollection.py +20 -1
  1855. office365/sharepoint/listitems/listitem.py +529 -27
  1856. office365/sharepoint/listitems/relateditemmanager.py +231 -1
  1857. office365/sharepoint/listitems/upsert.py +75 -0
  1858. office365/sharepoint/listitems/versions/version.py +9 -0
  1859. office365/sharepoint/lists/apihubconnector.py +18 -1
  1860. office365/sharepoint/lists/batch_convert_asset_result.py +19 -0
  1861. office365/sharepoint/lists/batch_convert_classic_wiki_page_input.py +15 -0
  1862. office365/sharepoint/lists/batch_convert_item_result.py +21 -1
  1863. office365/sharepoint/lists/bloom_filter.py +33 -0
  1864. office365/sharepoint/lists/collection.py +29 -22
  1865. office365/sharepoint/lists/exporter.py +4 -3
  1866. office365/sharepoint/lists/list.py +1637 -55
  1867. office365/sharepoint/lists/list_forms_api.py +106 -1
  1868. office365/sharepoint/lists/playlist.py +33 -1
  1869. office365/sharepoint/lists/recentlist.py +7 -0
  1870. office365/sharepoint/lists/recentlistcollection.py +76 -1
  1871. office365/sharepoint/lists/recentlistproxy.py +31 -1
  1872. office365/sharepoint/lists/recommendationcollection.py +71 -1
  1873. office365/sharepoint/lists/smart_wiki_library_utility.py +160 -0
  1874. office365/sharepoint/lists/smart_wiki_metadata_update_parameters.py +18 -0
  1875. office365/sharepoint/lists/templates/template.py +58 -0
  1876. office365/sharepoint/lists/version_policy_manager.py +14 -0
  1877. office365/sharepoint/logger/export.py +12 -0
  1878. office365/sharepoint/marketplace/app_metadata.py +97 -1
  1879. office365/sharepoint/marketplace/appstatequeryjobdefinition.py +9 -0
  1880. office365/sharepoint/marketplace/corporatecuratedgallery/carddesigns/card_designs.py +35 -0
  1881. office365/sharepoint/marketplace/sitecollection/appcatalog/allowed_item.py +5 -0
  1882. office365/sharepoint/marketplace/tenant/appcatalog/accessor.py +107 -30
  1883. office365/sharepoint/microfeed/data.py +0 -6
  1884. office365/sharepoint/microservice/manager.py +61 -0
  1885. office365/sharepoint/migrationcenter/agentgroupentity.py +24 -1
  1886. office365/sharepoint/migrationcenter/common/task.py +197 -1
  1887. office365/sharepoint/migrationcenter/common/task_entity_data.py +232 -1
  1888. office365/sharepoint/migrationcenter/common/teams/channel_resource.py +7 -0
  1889. office365/sharepoint/migrationcenter/common/teams/team_resource.py +8 -0
  1890. office365/sharepoint/migrationcenter/common/url_parser.py +37 -1
  1891. office365/sharepoint/migrationcenter/credentialentitydata.py +7 -0
  1892. office365/sharepoint/migrationcenter/deploy_status.py +13 -0
  1893. office365/sharepoint/migrationcenter/device.py +7 -0
  1894. office365/sharepoint/migrationcenter/deviceentitydata.py +8 -0
  1895. office365/sharepoint/migrationcenter/service/credential.py +21 -0
  1896. office365/sharepoint/migrationcenter/service/properties.py +20 -0
  1897. office365/sharepoint/migrationcenter/service/services.py +77 -0
  1898. office365/sharepoint/migrationcenter/service/storage.py +34 -0
  1899. office365/sharepoint/migrationcenter/spflight.py +13 -0
  1900. office365/sharepoint/migrationcenter/urlparseresult.py +77 -0
  1901. office365/sharepoint/mount/folder_info.py +34 -0
  1902. office365/sharepoint/mount/onedriveitemcollection.py +26 -1
  1903. office365/sharepoint/mount/placesinformation.py +18 -1
  1904. office365/sharepoint/multigeo/service/allowed_data_location.py +7 -0
  1905. office365/sharepoint/multigeo/service/cross_geo_user_placement_job.py +7 -0
  1906. office365/sharepoint/multigeo/service/df_deprecation_job.py +18 -0
  1907. office365/sharepoint/multigeo/service/geo_tenant_instance_information.py +7 -0
  1908. office365/sharepoint/multigeo/service/job_entity_data.py +21 -0
  1909. office365/sharepoint/multigeo/service/microfeedpostdefinitionmanager.py +91 -0
  1910. office365/sharepoint/multigeo/service/move_job_entity_data.py +111 -0
  1911. office365/sharepoint/multigeo/service/move_site_ro_state.py +18 -0
  1912. office365/sharepoint/multigeo/service/multigeoservicesbeta.py +55 -13
  1913. office365/sharepoint/multigeo/service/sbsitemovejob.py +26 -0
  1914. office365/sharepoint/multigeo/service/site_move_job_entity_data.py +75 -0
  1915. office365/sharepoint/multigeo/service/spmultigeoproxy.py +13 -0
  1916. office365/sharepoint/multigeo/service/storage_quota.py +49 -0
  1917. office365/sharepoint/multigeo/service/tenant_information.py +40 -0
  1918. office365/sharepoint/multigeo/service/unified_group.py +35 -0
  1919. office365/sharepoint/multigeo/service/user_personal_site_location.py +30 -0
  1920. office365/sharepoint/multigeo/service/usermovejob.py +11 -0
  1921. office365/sharepoint/navigation/home_site_navigation_settings.py +6 -1
  1922. office365/sharepoint/navigation/nodes/creationinformation.py +2 -0
  1923. office365/sharepoint/navigation/nodes/node.py +22 -1
  1924. office365/sharepoint/navigation/quickaccessitemcollection.py +37 -1
  1925. office365/sharepoint/navigation/servicerest.py +127 -0
  1926. office365/sharepoint/news/ngspdatacollection.py +24 -1
  1927. office365/sharepoint/ngsp_ai_settings.py +32 -0
  1928. office365/sharepoint/oauth/authentication.py +13 -0
  1929. office365/sharepoint/oauth/token_response.py +56 -0
  1930. office365/sharepoint/onboarding/job_entity_data.py +14 -0
  1931. office365/sharepoint/onboarding/tenantrename/job.py +7 -0
  1932. office365/sharepoint/onboarding/tenantrename/jobentitydata.py +10 -0
  1933. office365/sharepoint/permissions/irm/effective_settings.py +78 -0
  1934. office365/sharepoint/permissions/irm/file_settings.py +47 -0
  1935. office365/sharepoint/permissions/irm/settings.py +16 -0
  1936. office365/sharepoint/permissions/roles/definitions/definition.py +12 -0
  1937. office365/sharepoint/permissions/securable_object.py +42 -0
  1938. office365/sharepoint/portal/groups/site_manager.py +28 -4
  1939. office365/sharepoint/portal/home/page_context.py +4 -0
  1940. office365/sharepoint/portal/home/service_context.py +57 -0
  1941. office365/sharepoint/portal/organization_news.py +37 -0
  1942. office365/sharepoint/portal/theme_manager.py +137 -8
  1943. office365/sharepoint/portal/userprofiles/sharedwithme/document.py +267 -0
  1944. office365/sharepoint/portal/userprofiles/sharedwithme/item_collection.py +147 -0
  1945. office365/sharepoint/portal/webcontrols/recentdocument.py +7 -0
  1946. office365/sharepoint/principal/groups/group.py +11 -1
  1947. office365/sharepoint/principal/users/user.py +10 -0
  1948. office365/sharepoint/publishing/amplify/clientamplifyanywhereresults.py +1 -1
  1949. office365/sharepoint/publishing/amplify/historyresult.py +1 -1
  1950. office365/sharepoint/publishing/amplify/result.py +1 -1
  1951. office365/sharepoint/publishing/announcements/data.py +2 -2
  1952. office365/sharepoint/publishing/approval/request.py +7 -0
  1953. office365/sharepoint/publishing/campaign/campaign.py +45 -1
  1954. office365/sharepoint/publishing/channelannouncement.py +3 -3
  1955. office365/sharepoint/publishing/customproperties/base.py +19 -0
  1956. office365/sharepoint/publishing/customproperties/bigint.py +9 -0
  1957. office365/sharepoint/publishing/diagnostics/page_result.py +2 -2
  1958. office365/sharepoint/publishing/embed_data_v1.py +7 -0
  1959. office365/sharepoint/publishing/feedvideopage.py +0 -7
  1960. office365/sharepoint/publishing/highlights_info.py +14 -0
  1961. office365/sharepoint/publishing/pagecopywithassets/response.py +79 -0
  1962. office365/sharepoint/publishing/pages/_3d/__init__.py +0 -0
  1963. office365/sharepoint/publishing/pages/_3d/page.py +319 -0
  1964. office365/sharepoint/publishing/pages/campaign/publication.py +104 -16
  1965. office365/sharepoint/publishing/pages/canvas.py +81 -0
  1966. office365/sharepoint/publishing/pages/collection.py +39 -5
  1967. office365/sharepoint/publishing/pages/metadata.py +119 -0
  1968. office365/sharepoint/publishing/pages/move_response.py +64 -0
  1969. office365/sharepoint/publishing/pages/page.py +6 -117
  1970. office365/sharepoint/publishing/pages/reposts/metadata.py +30 -0
  1971. office365/sharepoint/publishing/pages/reposts/repost.py +0 -7
  1972. office365/sharepoint/publishing/pages/topics/topic.py +0 -7
  1973. office365/sharepoint/publishing/person/magazineuserprofile.py +3 -3
  1974. office365/sharepoint/publishing/personmagazine/userprofiledata.py +1 -1
  1975. office365/sharepoint/publishing/point/site_status.py +25 -0
  1976. office365/sharepoint/publishing/point/user.py +7 -0
  1977. office365/sharepoint/publishing/profiledata.py +1 -1
  1978. office365/sharepoint/publishing/profilefullproperties.py +3 -3
  1979. office365/sharepoint/publishing/profilevieweditpolicies.py +24 -24
  1980. office365/sharepoint/publishing/publicationmetadata.py +2 -2
  1981. office365/sharepoint/publishing/ruleerrordetails.py +1 -1
  1982. office365/sharepoint/publishing/ruleresult.py +1 -1
  1983. office365/sharepoint/publishing/search.py +8 -0
  1984. office365/sharepoint/publishing/sitepagstreamdata.py +1 -1
  1985. office365/sharepoint/publishing/spotlightchannel.py +19 -1
  1986. office365/sharepoint/publishing/spotlightvideo.py +19 -1
  1987. office365/sharepoint/publishing/spstatusresponse.py +1 -1
  1988. office365/sharepoint/publishing/statusresponse.py +2 -4
  1989. office365/sharepoint/publishing/subtitlefile.py +0 -40
  1990. office365/sharepoint/publishing/user_info.py +8 -0
  1991. office365/sharepoint/publishing/validations/prepublishvalidationserrorcodesforvivaengage.py +1 -1
  1992. office365/sharepoint/publishing/video/channel.py +7 -0
  1993. office365/sharepoint/publishing/video/item.py +11 -2
  1994. office365/sharepoint/publishing/video/service_manager.py +66 -2
  1995. office365/sharepoint/pushnotifications/subscriber.py +7 -0
  1996. office365/sharepoint/quotamanagement/consumer/consumer_quota_info_api.py +14 -0
  1997. office365/sharepoint/quotamanagement/consumer/non_quota_backfill_api.py +23 -0
  1998. office365/sharepoint/quotamanagement/consumer/nonquotamigrationapi.py +9 -0
  1999. office365/sharepoint/quotamanagement/consumer/quotamigrationapi.py +13 -0
  2000. office365/sharepoint/recyclebin/item.py +16 -0
  2001. office365/sharepoint/recyclebin/item_collection.py +1 -1
  2002. office365/sharepoint/request.py +124 -24
  2003. office365/sharepoint/request_context.py +41 -2
  2004. office365/sharepoint/role_definition_creation_information.py +14 -0
  2005. office365/sharepoint/search/administration/document_crawl_log.py +24 -7
  2006. office365/sharepoint/search/administration/providers/crawl_versions_info.py +29 -0
  2007. office365/sharepoint/search/administration/providers/recycle_bin_info.py +23 -0
  2008. office365/sharepoint/search/administration/providers/site_content_processing_info.py +67 -0
  2009. office365/sharepoint/search/relevant_results.py +7 -0
  2010. office365/sharepoint/search/result.py +6 -0
  2011. office365/sharepoint/search/searchresultitemcollection.py +86 -1
  2012. office365/sharepoint/search/semantic/enqueueproxy.py +68 -1
  2013. office365/sharepoint/search/semantic/itemcollection.py +35 -1
  2014. office365/sharepoint/search/service.py +7 -0
  2015. office365/sharepoint/search/simple_data_row.py +8 -0
  2016. office365/sharepoint/securestore/target_application.py +17 -0
  2017. office365/sharepoint/securestore/target_application_field.py +19 -0
  2018. office365/sharepoint/sharing/information.py +299 -1
  2019. office365/sharepoint/sharing/internal/sharing_restrictions.py +30 -0
  2020. office365/sharepoint/sharing/object_sharing_information.py +35 -0
  2021. office365/sharepoint/sharing/object_sharing_information_user.py +67 -0
  2022. office365/sharepoint/sharing/object_sharing_settings.py +143 -0
  2023. office365/sharepoint/sharing/permission_information.py +22 -0
  2024. office365/sharepoint/sharing/picker_settings.py +24 -0
  2025. office365/sharepoint/sharing/principal_info.py +25 -0
  2026. office365/sharepoint/sharing/shared_document_info.py +161 -0
  2027. office365/sharepoint/sharing/sharepoint_sharing_settings.py +85 -0
  2028. office365/sharepoint/sitedesigns/design_package_menu_contents.py +20 -0
  2029. office365/sharepoint/sitedesigns/principal.py +19 -0
  2030. office365/sharepoint/sitedesigns/run.py +43 -0
  2031. office365/sharepoint/sitedesigns/userfirstrun.py +53 -0
  2032. office365/sharepoint/sites/home/site.py +279 -0
  2033. office365/sharepoint/sites/language_collection.py +18 -0
  2034. office365/sharepoint/sites/migration/job_status.py +15 -0
  2035. office365/sharepoint/sites/site.py +984 -67
  2036. office365/sharepoint/sites/siteprovisioninginfoprovider.py +13 -0
  2037. office365/sharepoint/sites/team_site_data.py +45 -0
  2038. office365/sharepoint/sites/version_policy_manager.py +35 -0
  2039. office365/sharepoint/smartcache/item.py +106 -0
  2040. office365/sharepoint/social/feed/manager.py +208 -1
  2041. office365/sharepoint/social/following/manager.py +82 -1
  2042. office365/sharepoint/social/following/rest_manager.py +186 -0
  2043. office365/sharepoint/social/rest_actor.py +25 -0
  2044. office365/sharepoint/social/rest_thread.py +39 -1
  2045. office365/sharepoint/sp_playlist_subscriber.py +12 -0
  2046. office365/sharepoint/taxonomy/create_xml_parameters.py +5 -5
  2047. office365/sharepoint/taxonomy/field.py +20 -19
  2048. office365/sharepoint/taxonomy/field_value_col.py +21 -0
  2049. office365/sharepoint/taxonomy/groups/collection.py +19 -2
  2050. office365/sharepoint/teams/channel_manager.py +272 -0
  2051. office365/sharepoint/tenant/administration/app_service_principal_public.py +46 -0
  2052. office365/sharepoint/tenant/administration/audit/data.py +4 -1
  2053. office365/sharepoint/tenant/administration/consumer_quota_info_api.py +7 -0
  2054. office365/sharepoint/tenant/administration/container/filterorder.py +1 -1
  2055. office365/sharepoint/tenant/administration/container/properties.py +1 -1
  2056. office365/sharepoint/tenant/administration/container/type/configurationproperties.py +1 -1
  2057. office365/sharepoint/tenant/administration/copilot/reportrow.py +1 -1
  2058. office365/sharepoint/tenant/administration/datagovernance/insight_client.py +292 -23
  2059. office365/sharepoint/tenant/administration/dataset_metadata_request_info.py +4 -1
  2060. office365/sharepoint/tenant/administration/dataset_metadata_response.py +9 -2
  2061. office365/sharepoint/tenant/administration/ddiadapter.py +97 -0
  2062. office365/sharepoint/tenant/administration/endpoints.py +5 -0
  2063. office365/sharepoint/tenant/administration/groups/group.py +130 -0
  2064. office365/sharepoint/tenant/administration/hubsites/hub_site.py +62 -0
  2065. office365/sharepoint/tenant/administration/hubsites/properties.py +53 -0
  2066. office365/sharepoint/tenant/administration/internal/aad/collection.py +20 -0
  2067. office365/sharepoint/tenant/administration/internal/aad/permission_grant.py +35 -15
  2068. office365/sharepoint/tenant/administration/internal/appservice/permission_request.py +79 -1
  2069. office365/sharepoint/tenant/administration/internal/appservice/principal.py +85 -2
  2070. office365/sharepoint/tenant/administration/licensed_onedrives_summary_metrics.py +16 -0
  2071. office365/sharepoint/tenant/administration/malware/file.py +35 -0
  2072. office365/sharepoint/tenant/administration/odb_license_enforcement_service.py +26 -0
  2073. office365/sharepoint/tenant/administration/onedrives_count_and_size.py +15 -0
  2074. office365/sharepoint/tenant/administration/onedrives_summary_metrics.py +23 -0
  2075. office365/sharepoint/tenant/administration/onedrives_summary_metrics_by_unlicensed_reason.py +25 -0
  2076. office365/sharepoint/tenant/administration/owner_not_in_entra_onedrives_summary_metrics.py +22 -0
  2077. office365/sharepoint/tenant/administration/policies/content_security_configuration.py +67 -0
  2078. office365/sharepoint/tenant/administration/settings/service.py +240 -0
  2079. office365/sharepoint/tenant/administration/siteadministratorsfieldsdata.py +1 -1
  2080. office365/sharepoint/tenant/administration/sites/properties.py +578 -1
  2081. office365/sharepoint/tenant/administration/spcontenteventscustomemailproperty.py +1 -1
  2082. office365/sharepoint/tenant/administration/spdatagovernanceinsightresponse.py +6 -6
  2083. office365/sharepoint/tenant/administration/spdatagovernancesarrestapiclient.py +60 -1
  2084. office365/sharepoint/tenant/administration/spofileversionfiletypepolicysettings.py +1 -1
  2085. office365/sharepoint/tenant/administration/spom365agentinsightsm365agentsonsitesdetails.py +4 -0
  2086. office365/sharepoint/tenant/administration/storage_usage_metrics_snapshot.py +8 -1
  2087. office365/sharepoint/tenant/administration/syntex/applicationproperties.py +19 -3
  2088. office365/sharepoint/tenant/administration/syntex/getmodifiedlistresponse.py +1 -1
  2089. office365/sharepoint/tenant/administration/tenant.py +5931 -34
  2090. office365/sharepoint/tenant/administration/theme_properties.py +24 -0
  2091. office365/sharepoint/tenant/administration/unlicensed_onedrives_summary_metrics.py +20 -0
  2092. office365/sharepoint/tenant/apps/instance.py +20 -0
  2093. office365/sharepoint/tenant/apps/user_experience_state.py +25 -0
  2094. office365/sharepoint/tenant/insights/reports/manager.py +24 -12
  2095. office365/sharepoint/tenant/insights/reports/metadata.py +8 -0
  2096. office365/sharepoint/tenant/insights/reports/report.py +23 -0
  2097. office365/sharepoint/tenant/management/externalusers/results/remove.py +13 -0
  2098. office365/sharepoint/tenant/management/externalusers/results/session_revocation.py +9 -0
  2099. office365/sharepoint/tenant/management/office365_tenant.py +548 -8
  2100. office365/sharepoint/tenantadministration/catalog_management_collection.py +69 -0
  2101. office365/sharepoint/tenantadministration/catalog_management_custom_properties_collection.py +237 -0
  2102. office365/sharepoint/tenantadministration/catalog_management_restricted_content_discovery_collection.py +56 -0
  2103. office365/sharepoint/tenantadministration/sp_data_governance_client_exception.py +7 -0
  2104. office365/sharepoint/tenantadministration/sp_data_governance_insight_rest_api_client.py +475 -0
  2105. office365/sharepoint/tenantadministration/sp_data_governance_sar_rest_api_client.py +88 -0
  2106. office365/sharepoint/tenantadministration/spo_copilot_agent_insights_rest_api_client.py +170 -0
  2107. office365/sharepoint/tenantadministration/spo_file_archive_policy_info.py +4 -1
  2108. office365/sharepoint/tenantadministration/spo_restricted_content_discoverability_client.py +90 -0
  2109. office365/sharepoint/tenantadministration/spom365_agent_insights_rest_api_client.py +166 -0
  2110. office365/sharepoint/tenantadministration/spom365_agent_insights_top20_agents_details.py +11 -0
  2111. office365/sharepoint/tenantmanagement/group_creation_params.py +32 -0
  2112. office365/sharepoint/thresholds.py +529 -0
  2113. office365/sharepoint/token.py +7 -0
  2114. office365/sharepoint/translation/jobs/job.py +72 -2
  2115. office365/sharepoint/translation/jobs/status.py +47 -9
  2116. office365/sharepoint/translation/sync_translator.py +15 -2
  2117. office365/sharepoint/user_ai_tokens.py +56 -0
  2118. office365/sharepoint/user_photos.py +32 -0
  2119. office365/sharepoint/usercustomactions/action.py +109 -1
  2120. office365/sharepoint/userprofiles/followed_content.py +164 -0
  2121. office365/sharepoint/userprofiles/my_site_links.py +22 -0
  2122. office365/sharepoint/userprofiles/people_manager.py +68 -0
  2123. office365/sharepoint/userprofiles/peoplecollection.py +40 -1
  2124. office365/sharepoint/userprofiles/person_properties.py +22 -0
  2125. office365/sharepoint/userprofiles/personal_cache.py +246 -1
  2126. office365/sharepoint/userprofiles/personallistsproxy.py +33 -1
  2127. office365/sharepoint/userprofiles/profile_loader.py +16 -0
  2128. office365/sharepoint/userprofiles/user_profile.py +42 -0
  2129. office365/sharepoint/utilities/file_handler_wopi_properties.py +24 -0
  2130. office365/sharepoint/utilities/move_copy_util.py +46 -4
  2131. office365/sharepoint/utilities/upload_status.py +8 -0
  2132. office365/sharepoint/views/collection.py +135 -14
  2133. office365/sharepoint/views/field_collection.py +3 -0
  2134. office365/sharepoint/views/view.py +113 -0
  2135. office365/sharepoint/viva/app_configuration.py +34 -1
  2136. office365/sharepoint/viva/connections/page.py +27 -0
  2137. office365/sharepoint/viva/employee_engagement.py +149 -1
  2138. office365/sharepoint/viva/employee_experience_controller.py +97 -1
  2139. office365/sharepoint/viva/home.py +38 -0
  2140. office365/sharepoint/viva/knowledgehub.py +37 -1
  2141. office365/sharepoint/viva/learningmanager.py +9 -0
  2142. office365/sharepoint/viva/resource_get_endpoint.py +15 -0
  2143. office365/sharepoint/viva/visualizationappsynchronizationresult.py +18 -1
  2144. office365/sharepoint/viva/vivaresources.py +60 -0
  2145. office365/sharepoint/webhooks/subscription.py +2 -12
  2146. office365/sharepoint/webhooks/subscription_information.py +2 -1
  2147. office365/sharepoint/webparts/client/webpart.py +15 -0
  2148. office365/sharepoint/webparts/definitions/definition.py +13 -0
  2149. office365/sharepoint/webparts/limited_manager.py +29 -7
  2150. office365/sharepoint/webparts/webpart.py +12 -0
  2151. office365/sharepoint/webs/apptile.py +12 -0
  2152. office365/sharepoint/webs/context_web_information.py +14 -9
  2153. office365/sharepoint/webs/dataleakage_prevention_status_info.py +24 -0
  2154. office365/sharepoint/webs/information.py +7 -0
  2155. office365/sharepoint/webs/modernize_homepage_result.py +7 -0
  2156. office365/sharepoint/webs/multilingual_settings.py +19 -1
  2157. office365/sharepoint/webs/regional_settings.py +27 -0
  2158. office365/sharepoint/webs/remote_web.py +19 -0
  2159. office365/sharepoint/webs/templates/__init__.py +11 -0
  2160. office365/sharepoint/webs/templates/template.py +7 -0
  2161. office365/sharepoint/webs/templates/type.py +74 -15
  2162. office365/sharepoint/webs/theme_info.py +14 -0
  2163. office365/sharepoint/webs/time_zone.py +15 -0
  2164. office365/sharepoint/webs/web.py +1167 -0
  2165. office365/sharepoint/workflow/associations/association.py +5 -0
  2166. office365/sharepoint/workflow/definition.py +6 -0
  2167. office365/sharepoint/workflow/deployment_service.py +155 -0
  2168. office365/sharepoint/workflow/instances/instance.py +41 -0
  2169. office365/sharepoint/workflow/instances/service.py +33 -0
  2170. office365/sharepoint/workflow/interopservice.py +68 -0
  2171. office365/sharepoint/workflow/messagingservice.py +24 -0
  2172. office365/sharepoint/workflow/servicesmanager.py +41 -2
  2173. office365/sharepoint/workflow/sp_workflow_task.py +618 -0
  2174. office365/sharepoint/workflow/subscriptions/service.py +67 -0
  2175. office365/sharepoint/workflow/subscriptions/subscription.py +31 -0
  2176. office365/sharepoint/workflow/task.py +425 -0
  2177. office365/sharepoint/workflow/template.py +8 -0
  2178. office365/subscriptions/change_notification.py +17 -0
  2179. office365/subscriptions/change_notification_collection.py +4 -0
  2180. office365/subscriptions/changetype.py +4 -0
  2181. office365/subscriptions/collection.py +10 -6
  2182. office365/subscriptions/subscription.py +57 -1
  2183. office365/teams/admin_root.py +35 -0
  2184. office365/teams/administration/number_assignment.py +74 -1
  2185. office365/teams/administration/telephone_number_long_running_operation.py +26 -3
  2186. office365/teams/administration/telephone_number_management_root.py +20 -1
  2187. office365/teams/administration/user_configuration.py +17 -3
  2188. office365/teams/app_settings.py +21 -0
  2189. office365/teams/apps/app.py +11 -0
  2190. office365/teams/apps/definition.py +38 -0
  2191. office365/teams/apps/installation.py +18 -0
  2192. office365/teams/assignment_type.py +13 -0
  2193. office365/teams/channels/channel.py +59 -0
  2194. office365/teams/channels/collection.py +62 -2
  2195. office365/teams/channels/layout_type.py +13 -0
  2196. office365/teams/channels/shared_team_info.py +6 -0
  2197. office365/teams/chats/chat.py +40 -1
  2198. office365/teams/chats/collection.py +11 -3
  2199. office365/teams/chats/deleted.py +6 -0
  2200. office365/teams/chats/messages/info.py +42 -0
  2201. office365/teams/chats/messages/message.py +39 -1
  2202. office365/teams/chats/pinned_chat_message_info.py +22 -0
  2203. office365/teams/chats/targeted_chat_message.py +21 -0
  2204. office365/teams/collection.py +76 -11
  2205. office365/teams/community_privacy.py +13 -0
  2206. office365/teams/info.py +11 -0
  2207. office365/teams/members/aad_user_conversation.py +16 -0
  2208. office365/teams/members/conversation.py +17 -0
  2209. office365/teams/members/conversation_collection.py +19 -7
  2210. office365/teams/migration_mode.py +13 -0
  2211. office365/teams/operations/async_operation.py +102 -1
  2212. office365/teams/operations/asyncoperationtype.py +10 -15
  2213. office365/teams/policy_assignment.py +23 -0
  2214. office365/teams/schedule/change_request.py +47 -1
  2215. office365/teams/schedule/day_note.py +34 -0
  2216. office365/teams/schedule/groups/group.py +16 -0
  2217. office365/teams/schedule/open_shift.py +38 -0
  2218. office365/teams/schedule/schedule.py +165 -0
  2219. office365/teams/schedule/shifts/open/change_request.py +13 -0
  2220. office365/teams/schedule/shifts/shift.py +23 -0
  2221. office365/teams/schedule/swap_shifts_change_request.py +16 -0
  2222. office365/teams/schedule/time_card.py +74 -0
  2223. office365/teams/schedule/time_off.py +38 -0
  2224. office365/teams/schedule/time_off_reason.py +35 -0
  2225. office365/teams/schedule/time_off_request.py +27 -0
  2226. office365/teams/tabs/tab.py +18 -0
  2227. office365/teams/team.py +2 -2
  2228. office365/teams/teamwork/shiftmanagement/user_solution_root.py +22 -0
  2229. office365/teams/teamwork/shiftmanagement/working_time_schedule.py +9 -0
  2230. office365/teams/teamwork/tags/member.py +16 -0
  2231. office365/teams/telephone_number_long_running_operation_details.py +19 -0
  2232. office365/teams/viva/community.py +42 -1
  2233. office365/teams/viva/employee_experience.py +34 -0
  2234. office365/teams/viva/employee_experience_user.py +19 -0
  2235. office365/teams/viva/engagement/conversation.py +33 -1
  2236. office365/teams/viva/engagement/conversation_message.py +112 -0
  2237. office365/teams/viva/engagement/conversation_message_reaction.py +41 -0
  2238. office365/teams/viva/learning/content.py +111 -0
  2239. office365/teams/viva/learning/courses/activity.py +49 -0
  2240. office365/teams/viva/learning/courses/self_initiated.py +14 -0
  2241. office365/teams/viva/learning/provider.py +60 -0
  2242. office365/teams/work.py +43 -1
  2243. office365/teams/workforce_integration.py +69 -0
  2244. office365/teams/workforce_integration_encryption.py +18 -0
  2245. office365/todo/attachments/base.py +11 -0
  2246. office365/todo/attachments/session.py +4 -0
  2247. office365/todo/attachments/task_file.py +2 -5
  2248. office365/todo/attachments/type.py +7 -10
  2249. office365/todo/linked_resource.py +6 -0
  2250. office365/todo/tasks/collection.py +45 -0
  2251. office365/todo/tasks/lists/collection.py +1 -0
  2252. office365/todo/tasks/task.py +1 -1
  2253. office365_rest_python_client-3.3.0.dist-info/METADATA +635 -0
  2254. office365_rest_python_client-3.3.0.dist-info/RECORD +6789 -0
  2255. office365/directory/identitygovernance/workflow.py +0 -106
  2256. office365/directory/identitygovernance/workflow_setting.py +0 -15
  2257. office365/directory/identitygovernance/workflow_version.py +0 -16
  2258. office365/directory/security/account.py +0 -14
  2259. office365/directory/security/ai_agent_evidence.py +0 -16
  2260. office365/directory/security/alerts/alert.py +0 -205
  2261. office365/directory/security/alerts/blob_container_evidence.py +0 -17
  2262. office365/directory/security/alerts/blob_evidence.py +0 -21
  2263. office365/directory/security/alerts/collection.py +0 -49
  2264. office365/directory/security/alerts/evidence.py +0 -28
  2265. office365/directory/security/alerts/file_security_state.py +0 -5
  2266. office365/directory/security/alerts/history_state.py +0 -16
  2267. office365/directory/security/alerts/malware_evidence.py +0 -22
  2268. office365/directory/security/alerts/process_evidence.py +0 -27
  2269. office365/directory/security/alerts/sas_token_evidence.py +0 -26
  2270. office365/directory/security/analyzed_message_evidence.py +0 -34
  2271. office365/directory/security/article.py +0 -56
  2272. office365/directory/security/attacksimulations/automation.py +0 -30
  2273. office365/directory/security/attacksimulations/automation_run.py +0 -12
  2274. office365/directory/security/attacksimulations/event.py +0 -5
  2275. office365/directory/security/attacksimulations/landing_page.py +0 -5
  2276. office365/directory/security/attacksimulations/operations/operation.py +0 -5
  2277. office365/directory/security/attacksimulations/repeat_offender.py +0 -17
  2278. office365/directory/security/attacksimulations/reports/overview.py +0 -5
  2279. office365/directory/security/attacksimulations/reports/report.py +0 -25
  2280. office365/directory/security/attacksimulations/root.py +0 -67
  2281. office365/directory/security/attacksimulations/simulation.py +0 -23
  2282. office365/directory/security/attacksimulations/user.py +0 -16
  2283. office365/directory/security/attacksimulations/user_coverage.py +0 -10
  2284. office365/directory/security/attacksimulations/users/details.py +0 -20
  2285. office365/directory/security/attribute_definition.py +0 -37
  2286. office365/directory/security/attribute_mapping.py +0 -23
  2287. office365/directory/security/attribute_mapping_source.py +0 -24
  2288. office365/directory/security/audit/audit_data.py +0 -15
  2289. office365/directory/security/audit/whois_record.py +0 -22
  2290. office365/directory/security/cases/case.py +0 -48
  2291. office365/directory/security/cases/ediscovery.py +0 -99
  2292. office365/directory/security/cases/operation.py +0 -10
  2293. office365/directory/security/cases/root.py +0 -21
  2294. office365/directory/security/category_template.py +0 -9
  2295. office365/directory/security/cloud_application_evidence.py +0 -20
  2296. office365/directory/security/cloud_logon_session_evidence.py +0 -24
  2297. office365/directory/security/collaboration/analyzed_email.py +0 -133
  2298. office365/directory/security/collaboration/analyzed_email_attachment.py +0 -22
  2299. office365/directory/security/collaboration/analyzed_email_delivery_detail.py +0 -15
  2300. office365/directory/security/collaboration/analyzed_email_url.py +0 -18
  2301. office365/directory/security/collaboration/collaboration_root.py +0 -22
  2302. office365/directory/security/compromise_indicator.py +0 -14
  2303. office365/directory/security/container_evidence.py +0 -23
  2304. office365/directory/security/container_image_evidence.py +0 -17
  2305. office365/directory/security/cvss_summary.py +0 -15
  2306. office365/directory/security/data_source_container.py +0 -44
  2307. office365/directory/security/datasecurity/classifcation_error_base.py +0 -18
  2308. office365/directory/security/datasecurity/classification_error.py +0 -12
  2309. office365/directory/security/datasecurity/compute_rights_and_inheritance_result.py +0 -17
  2310. office365/directory/security/datasecurity/governance.py +0 -17
  2311. office365/directory/security/datasecurity/policy_scope_base.py +0 -26
  2312. office365/directory/security/datasecurity/policy_tenant_scope.py +0 -15
  2313. office365/directory/security/datasecurity/policy_tip_action.py +0 -16
  2314. office365/directory/security/datasecurity/process_content_batch_request.py +0 -17
  2315. office365/directory/security/datasecurity/process_content_request.py +0 -24
  2316. office365/directory/security/datasecurity/process_content_response.py +0 -24
  2317. office365/directory/security/datasecurity/process_content_responses.py +0 -16
  2318. office365/directory/security/datasecurity/process_file_metadata.py +0 -16
  2319. office365/directory/security/datasecurity/sensitivity_label.py +0 -31
  2320. office365/directory/security/detonation_details.py +0 -34
  2321. office365/directory/security/device_evidence.py +0 -47
  2322. office365/directory/security/dns_evidence.py +0 -19
  2323. office365/directory/security/ediscovery/case_member.py +0 -21
  2324. office365/directory/security/ediscovery/custodian.py +0 -22
  2325. office365/directory/security/ediscovery/ediscovery_case_settings.py +0 -21
  2326. office365/directory/security/ediscovery/ediscovery_estimate_operation.py +0 -54
  2327. office365/directory/security/ediscovery/ediscovery_export_operation.py +0 -50
  2328. office365/directory/security/ediscovery/ediscovery_index_operation.py +0 -7
  2329. office365/directory/security/ediscovery/ediscovery_review_tag.py +0 -34
  2330. office365/directory/security/ediscovery/noncustodial_data_source.py +0 -18
  2331. office365/directory/security/ediscovery/operations/add_to_review_set.py +0 -52
  2332. office365/directory/security/ediscovery/operations/hold.py +0 -7
  2333. office365/directory/security/ediscovery/operations/hold_policy_sync.py +0 -9
  2334. office365/directory/security/ediscovery/operations/purge_data.py +0 -9
  2335. office365/directory/security/ediscovery/operations/search_export.py +0 -62
  2336. office365/directory/security/ediscovery/operations/tag.py +0 -7
  2337. office365/directory/security/ediscovery/review_set.py +0 -22
  2338. office365/directory/security/ediscovery/review_set_query.py +0 -7
  2339. office365/directory/security/ediscovery/search.py +0 -56
  2340. office365/directory/security/event_propagation_result.py +0 -18
  2341. office365/directory/security/event_query.py +0 -14
  2342. office365/directory/security/expression_input_object.py +0 -20
  2343. office365/directory/security/file_evidence.py +0 -18
  2344. office365/directory/security/file_hash.py +0 -16
  2345. office365/directory/security/file_hash_evidence.py +0 -16
  2346. office365/directory/security/file_plan_applied_category.py +0 -15
  2347. office365/directory/security/filter.py +0 -22
  2348. office365/directory/security/filter_clause.py +0 -17
  2349. office365/directory/security/filter_group.py +0 -17
  2350. office365/directory/security/formatted_content.py +0 -16
  2351. office365/directory/security/google_cloud_resource_evidence.py +0 -21
  2352. office365/directory/security/health_issue.py +0 -81
  2353. office365/directory/security/hunting_query_results.py +0 -24
  2354. office365/directory/security/identity_accounts.py +0 -36
  2355. office365/directory/security/incidents/incident.py +0 -59
  2356. office365/directory/security/indicator.py +0 -16
  2357. office365/directory/security/invoke_action_result.py +0 -15
  2358. office365/directory/security/io_t_device_evidence.py +0 -46
  2359. office365/directory/security/ip_address.py +0 -26
  2360. office365/directory/security/ip_evidence.py +0 -19
  2361. office365/directory/security/kubernetes_cluster_evidence.py +0 -20
  2362. office365/directory/security/kubernetes_controller_evidence.py +0 -19
  2363. office365/directory/security/kubernetes_namespace_evidence.py +0 -18
  2364. office365/directory/security/kubernetes_pod_evidence.py +0 -35
  2365. office365/directory/security/kubernetes_secret_evidence.py +0 -17
  2366. office365/directory/security/kubernetes_service_account_evidence.py +0 -16
  2367. office365/directory/security/kubernetes_service_evidence.py +0 -29
  2368. office365/directory/security/kubernetes_service_port.py +0 -20
  2369. office365/directory/security/labels/retention/collection.py +0 -68
  2370. office365/directory/security/labels/retention/duration_in_days.py +0 -16
  2371. office365/directory/security/labels/retention/fileplan_descriptor.py +0 -52
  2372. office365/directory/security/labels/retention/label.py +0 -158
  2373. office365/directory/security/labels/root.py +0 -83
  2374. office365/directory/security/mailbox_configuration_evidence.py +0 -19
  2375. office365/directory/security/mailbox_evidence.py +0 -18
  2376. office365/directory/security/network_connection_evidence.py +0 -18
  2377. office365/directory/security/nic_evidence.py +0 -18
  2378. office365/directory/security/object_definition.py +0 -25
  2379. office365/directory/security/object_mapping.py +0 -26
  2380. office365/directory/security/parse_expression_response.py +0 -19
  2381. office365/directory/security/passive_dns_record.py +0 -47
  2382. office365/directory/security/processing_error.py +0 -15
  2383. office365/directory/security/retention_event.py +0 -63
  2384. office365/directory/security/retention_event_status.py +0 -15
  2385. office365/directory/security/scorecontrol/profile.py +0 -23
  2386. office365/directory/security/search/data_source.py +0 -34
  2387. office365/directory/security/security.py +0 -157
  2388. office365/directory/security/sensor.py +0 -72
  2389. office365/directory/security/sensor_candidate_activation_configuration.py +0 -9
  2390. office365/directory/security/sensor_settings.py +0 -20
  2391. office365/directory/security/service_principal_evidence.py +0 -18
  2392. office365/directory/security/settings_container.py +0 -19
  2393. office365/directory/security/ssl_certificate.py +0 -59
  2394. office365/directory/security/string_key_attribute_mapping_source_value_pair.py +0 -16
  2395. office365/directory/security/subdomain.py +0 -26
  2396. office365/directory/security/subjectrightsrequests/identity.py +0 -21
  2397. office365/directory/security/subjectrightsrequests/request.py +0 -6
  2398. office365/directory/security/teams_message_evidence.py +0 -42
  2399. office365/directory/security/threatintelligence/host.py +0 -138
  2400. office365/directory/security/threatintelligence/host_component.py +0 -46
  2401. office365/directory/security/threatintelligence/host_cookie.py +0 -41
  2402. office365/directory/security/threatintelligence/host_logon_session_evidence.py +0 -21
  2403. office365/directory/security/threatintelligence/host_pair.py +0 -41
  2404. office365/directory/security/threatintelligence/host_port.py +0 -57
  2405. office365/directory/security/threatintelligence/host_port_component.py +0 -19
  2406. office365/directory/security/threatintelligence/host_reputation.py +0 -16
  2407. office365/directory/security/threatintelligence/host_reputation_rule.py +0 -16
  2408. office365/directory/security/threatintelligence/host_ssl_certificate.py +0 -43
  2409. office365/directory/security/threatintelligence/host_tracker.py +0 -41
  2410. office365/directory/security/threatintelligence/profile.py +0 -56
  2411. office365/directory/security/threatintelligence/threat_intelligence.py +0 -193
  2412. office365/directory/security/timeline_event.py +0 -19
  2413. office365/directory/security/triggers/root.py +0 -9
  2414. office365/directory/security/triggertypes/collection.py +0 -9
  2415. office365/directory/security/triggertypes/root.py +0 -24
  2416. office365/directory/security/unified_group_source.py +0 -22
  2417. office365/directory/security/user_account.py +0 -27
  2418. office365/directory/security/user_evidence.py +0 -17
  2419. office365/directory/security/user_source.py +0 -27
  2420. office365/directory/security/vm_metadata.py +0 -16
  2421. office365/directory/security/vulnerability.py +0 -74
  2422. office365/directory/security/whois_base_record.py +0 -59
  2423. office365/externalconnectors/binary_operator.py +0 -12
  2424. office365/externalconnectors/connection_operation_status.py +0 -15
  2425. office365/externalconnectors/connection_state.py +0 -15
  2426. office365/externalconnectors/external_activity_type.py +0 -15
  2427. office365/externalconnectors/external_item_content_type.py +0 -13
  2428. office365/intune/brand.py +0 -21
  2429. office365/intune/instance_resource_access.py +0 -19
  2430. office365/intune/provisioned_plan.py +0 -27
  2431. office365/migration/_util.py +0 -73
  2432. office365/onenote/operations/operation.py +0 -35
  2433. office365/partners/billing/billing_period.py +0 -13
  2434. office365/partners/billing/billing_reconciliation.py +0 -26
  2435. office365/sharepoint/contentcenter/machinelearning/publications/result.py +0 -9
  2436. office365/sharepoint/customactions/action.py +0 -36
  2437. office365/sharepoint/listitems/caml/types.py +0 -70
  2438. office365/sharepoint/publishing/pages/3d/page.py +0 -325
  2439. office365_rest_python_client-3.1.0.dist-info/METADATA +0 -475
  2440. office365_rest_python_client-3.1.0.dist-info/RECORD +0 -5686
  2441. /office365/{directory/security → common}/__init__.py +0 -0
  2442. /office365/{intune → directory/applications}/resource_permission.py +0 -0
  2443. /office365/directory/identitygovernance/{workflow_subject.py → workflow/subject.py} +0 -0
  2444. /office365/{directory/security/alerts → intune/devices/configurations/macos}/__init__.py +0 -0
  2445. /office365/{directory/security/attacksimulations → intune/devices/configurations/windows/_10}/__init__.py +0 -0
  2446. /office365/intune/devices/configurations/windows/{10 → _10}/editiontype.py +0 -0
  2447. /office365/intune/{enrollment_state.py → devices/management/enrollment_state.py} +0 -0
  2448. /office365/{directory/security/attacksimulations/operations → intune/devices/management/mobileapps/macos}/__init__.py +0 -0
  2449. /office365/intune/{package_status.py → devices/management/package_status.py} +0 -0
  2450. /office365/intune/{process_integrity_level.py → devices/management/process_integrity_level.py} +0 -0
  2451. /office365/{directory/security/attacksimulations/reports → planner/internal}/__init__.py +0 -0
  2452. /office365/{directory/security/attacksimulations/users → planner/internal/paths}/__init__.py +0 -0
  2453. /office365/runtime/{decorators.py → deprecated.py} +0 -0
  2454. /office365/{directory/security/audit → security}/__init__.py +0 -0
  2455. /office365/{directory/security → security}/a365_ai_inference_call.py +0 -0
  2456. /office365/{directory/security → security}/a365_ai_invoke_agent.py +0 -0
  2457. /office365/{directory/security → security}/a365_ai_run_summary.py +0 -0
  2458. /office365/{directory/security → security}/a365_span_outputs.py +0 -0
  2459. /office365/{directory/security → security}/action.py +0 -0
  2460. /office365/{directory/security → security}/aed_audit_record.py +0 -0
  2461. /office365/{directory/security → security}/agent_admin_activity_record.py +0 -0
  2462. /office365/{directory/security → security}/agent_setting_admin_activity.py +0 -0
  2463. /office365/{directory/security → security}/ai_agent_platform.py +0 -0
  2464. /office365/{directory/security → security}/aip_discover.py +0 -0
  2465. /office365/{directory/security → security}/aip_file_deleted.py +0 -0
  2466. /office365/{directory/security → security}/aip_heart_beat.py +0 -0
  2467. /office365/{directory/security → security}/aip_protection_action_log_request.py +0 -0
  2468. /office365/{directory/security → security}/aip_scanner_discover_event.py +0 -0
  2469. /office365/{directory/security → security}/aip_sensitivity_label_action_log_request.py +0 -0
  2470. /office365/{directory/security → security}/air_admin_action_investigation_data.py +0 -0
  2471. /office365/{directory/security → security}/air_investigation_data.py +0 -0
  2472. /office365/{directory/security/cases → security/alerts}/__init__.py +0 -0
  2473. /office365/{directory/security → security}/alerts/active_directory_domain_evidence.py +0 -0
  2474. /office365/{directory/security → security}/alerts/antispamteamsdirection.py +0 -0
  2475. /office365/{directory/security → security}/alerts/azure_resource_evidence.py +0 -0
  2476. /office365/{directory/security → security}/alerts/classification.py +0 -0
  2477. /office365/{directory/security → security}/alerts/comment.py +0 -0
  2478. /office365/{directory/security → security}/alerts/connection_direction.py +0 -0
  2479. /office365/{directory/security → security}/alerts/connectionstatus.py +0 -0
  2480. /office365/{directory/security → security}/alerts/defenderavstatus.py +0 -0
  2481. /office365/{directory/security → security}/alerts/detectionsource.py +0 -0
  2482. /office365/{directory/security → security}/alerts/detectionstatus.py +0 -0
  2483. /office365/{directory/security → security}/alerts/determination.py +0 -0
  2484. /office365/{directory/security → security}/alerts/emailrole.py +0 -0
  2485. /office365/{directory/security → security}/alerts/evidenceremediationstatus.py +0 -0
  2486. /office365/{directory/security → security}/alerts/evidencerole.py +0 -0
  2487. /office365/{directory/security → security}/alerts/evidenceverdict.py +0 -0
  2488. /office365/{directory/security → security}/alerts/feedback.py +0 -0
  2489. /office365/{directory/security → security}/alerts/googlecloudlocationtype.py +0 -0
  2490. /office365/{directory/security → security}/alerts/iotdeviceimportancetype.py +0 -0
  2491. /office365/{directory/security → security}/alerts/kubernetesplatform.py +0 -0
  2492. /office365/{directory/security → security}/alerts/kubernetesservicetype.py +0 -0
  2493. /office365/{directory/security → security}/alerts/logontype.py +0 -0
  2494. /office365/{directory/security → security}/alerts/registryhive.py +0 -0
  2495. /office365/{directory/security → security}/alerts/registryoperation.py +0 -0
  2496. /office365/{directory/security → security}/alerts/registryvaluetype.py +0 -0
  2497. /office365/{directory/security → security}/alerts/securitynetworkprotocol.py +0 -0
  2498. /office365/{directory/security → security}/alerts/securityresourcetype.py +0 -0
  2499. /office365/{directory/security → security}/alerts/severity.py +0 -0
  2500. /office365/{directory/security → security}/alerts/status.py +0 -0
  2501. /office365/{directory/security → security}/alerts/useraccountsecuritytype.py +0 -0
  2502. /office365/{directory/security → security}/amazon_resource_evidence.py +0 -0
  2503. /office365/{directory/security → security}/antispam_directionality.py +0 -0
  2504. /office365/{directory/security → security}/artifact.py +0 -0
  2505. /office365/{directory/security/collaboration → security/attacksimulations}/__init__.py +0 -0
  2506. /office365/{directory/security → security}/attacksimulations/account_target_content_type.py +0 -0
  2507. /office365/{directory/security → security}/attacksimulations/clicksource.py +0 -0
  2508. /office365/{directory/security → security}/attacksimulations/endusernotificationpreference.py +0 -0
  2509. /office365/{directory/security → security}/attacksimulations/endusernotificationsettingtype.py +0 -0
  2510. /office365/{directory/security → security}/attacksimulations/endusernotificationtype.py +0 -0
  2511. /office365/{directory/security → security}/attacksimulations/notificationdeliveryfrequency.py +0 -0
  2512. /office365/{directory/security → security}/attacksimulations/notificationdeliverypreference.py +0 -0
  2513. /office365/{directory/security → security}/attacksimulations/oauthappscope.py +0 -0
  2514. /office365/{directory/security/datasecurity → security/attacksimulations/operations}/__init__.py +0 -0
  2515. /office365/{directory/security → security}/attacksimulations/operations/type.py +0 -0
  2516. /office365/{directory/security → security}/attacksimulations/payloadbrand.py +0 -0
  2517. /office365/{directory/security → security}/attacksimulations/payloadcomplexity.py +0 -0
  2518. /office365/{directory/security → security}/attacksimulations/payloaddeliveryplatform.py +0 -0
  2519. /office365/{directory/security → security}/attacksimulations/payloadindustry.py +0 -0
  2520. /office365/{directory/security → security}/attacksimulations/payloadtheme.py +0 -0
  2521. /office365/{directory/security/ediscovery → security/attacksimulations/reports}/__init__.py +0 -0
  2522. /office365/{directory/security → security}/attacksimulations/simulationattacktechnique.py +0 -0
  2523. /office365/{directory/security → security}/attacksimulations/simulationattacktype.py +0 -0
  2524. /office365/{directory/security → security}/attacksimulations/simulationautomationrunstatus.py +0 -0
  2525. /office365/{directory/security → security}/attacksimulations/simulationautomationstatus.py +0 -0
  2526. /office365/{directory/security → security}/attacksimulations/simulationcontentsource.py +0 -0
  2527. /office365/{directory/security → security}/attacksimulations/simulationcontentstatus.py +0 -0
  2528. /office365/{directory/security → security}/attacksimulations/simulationstatus.py +0 -0
  2529. /office365/{directory/security → security}/attacksimulations/targettedusertype.py +0 -0
  2530. /office365/{directory/security → security}/attacksimulations/trainingassignedto.py +0 -0
  2531. /office365/{directory/security → security}/attacksimulations/trainingavailabilitystatus.py +0 -0
  2532. /office365/{directory/security → security}/attacksimulations/trainingcompletionduration.py +0 -0
  2533. /office365/{directory/security → security}/attacksimulations/trainingsettingtype.py +0 -0
  2534. /office365/{directory/security → security}/attacksimulations/trainingstatus.py +0 -0
  2535. /office365/{directory/security → security}/attacksimulations/trainingtype.py +0 -0
  2536. /office365/{directory/security/ediscovery/operations → security/attacksimulations/users}/__init__.py +0 -0
  2537. /office365/{directory/security → security}/attribute_definition_metadata_entry.py +0 -0
  2538. /office365/{directory/security → security}/attribute_mapping_parameter_schema.py +0 -0
  2539. /office365/{directory/security/healthissues → security/audit}/__init__.py +0 -0
  2540. /office365/{directory/security → security}/audit/a365_ai_execute_tool.py +0 -0
  2541. /office365/{directory/security → security}/audit/aad_risk_detection_audit_record.py +0 -0
  2542. /office365/{directory/security → security}/audit/ai_app_interaction_audit_record.py +0 -0
  2543. /office365/{directory/security → security}/audit/ai_execute_tool_audit_record.py +0 -0
  2544. /office365/{directory/security → security}/audit/ai_interactions_change_notification_audit_record.py +0 -0
  2545. /office365/{directory/security → security}/audit/ai_interactions_export_audit_record.py +0 -0
  2546. /office365/{directory/security → security}/audit/ai_interactions_subscription_audit_record.py +0 -0
  2547. /office365/{directory/security → security}/audit/ai_invoke_agent_audit_record.py +0 -0
  2548. /office365/{directory/security → security}/audit/ai_span_outputs_audit_record.py +0 -0
  2549. /office365/{directory/security → security}/audit/air_manual_investigation_data.py +0 -0
  2550. /office365/{directory/security → security}/audit/alert_submission_audit_record.py +0 -0
  2551. /office365/{directory/security → security}/audit/alert_submission_result_detail_audit_record.py +0 -0
  2552. /office365/{directory/security → security}/audit/attack_sim_admin_audit_record.py +0 -0
  2553. /office365/{directory/security → security}/audit/attack_sim_audit_record.py +0 -0
  2554. /office365/{directory/security → security}/audit/audit_config_audit_record.py +0 -0
  2555. /office365/{directory/security → security}/audit/audit_log_query_status.py +0 -0
  2556. /office365/{directory/security → security}/audit/audit_record_type_dictionary.py +0 -0
  2557. /office365/{directory/security → security}/audit/audit_search_audit_record.py +0 -0
  2558. /office365/{directory/security → security}/audit/azfw_application_rule_aggregation_event_record.py +0 -0
  2559. /office365/{directory/security → security}/audit/azfw_dns_query_event_record.py +0 -0
  2560. /office365/{directory/security → security}/audit/azfw_network_rule_event_record.py +0 -0
  2561. /office365/{directory/security → security}/audit/azure_active_directory_account_logon_audit_record.py +0 -0
  2562. /office365/{directory/security → security}/audit/azure_active_directory_audit_record.py +0 -0
  2563. /office365/{directory/security → security}/audit/azure_active_directory_sts_logon_audit_record.py +0 -0
  2564. /office365/{directory/security → security}/audit/azure_ai_search_audit_record.py +0 -0
  2565. /office365/{directory/security → security}/audit/campaign_audit_record.py +0 -0
  2566. /office365/{directory/security → security}/audit/ccrai_policy_violation_record.py +0 -0
  2567. /office365/{directory/security → security}/audit/cdp_classifier_health_record.py +0 -0
  2568. /office365/{directory/security → security}/audit/cdp_cold_crawl_status_record.py +0 -0
  2569. /office365/{directory/security → security}/audit/cdp_consumption_resource_record.py +0 -0
  2570. /office365/{directory/security → security}/audit/cdp_content_explorer_aggregate_record.py +0 -0
  2571. /office365/{directory/security → security}/audit/cdp_dlp_sensitive_endpoint_audit_record.py +0 -0
  2572. /office365/{directory/security → security}/audit/cdp_log_record.py +0 -0
  2573. /office365/{directory/security → security}/audit/cdp_ocr_billing_record.py +0 -0
  2574. /office365/{directory/security → security}/audit/cdp_resource_scope_change_event_record.py +0 -0
  2575. /office365/{directory/security → security}/audit/cdpdlmai_interaction_insights_record.py +0 -0
  2576. /office365/{directory/security → security}/audit/cloud_update_device_config_audit_record.py +0 -0
  2577. /office365/{directory/security → security}/audit/cloud_update_profile_config_audit_record.py +0 -0
  2578. /office365/{directory/security → security}/audit/cloud_update_tenant_config_audit_record.py +0 -0
  2579. /office365/{directory/security → security}/audit/compliance_connector_audit_record.py +0 -0
  2580. /office365/{directory/security → security}/audit/compliance_dlm_exchange_audit_record.py +0 -0
  2581. /office365/{directory/security → security}/audit/compliance_dlm_share_point_audit_record.py +0 -0
  2582. /office365/{directory/security → security}/audit/compliance_dlp_applications_audit_record.py +0 -0
  2583. /office365/{directory/security → security}/audit/compliance_dlp_applications_classification_audit_record.py +0 -0
  2584. /office365/{directory/security → security}/audit/compliance_dlp_endpoint_audit_record.py +0 -0
  2585. /office365/{directory/security → security}/audit/compliance_dlp_endpoint_discovery_audit_record.py +0 -0
  2586. /office365/{directory/security → security}/audit/compliance_dlp_enforcement_audit_record.py +0 -0
  2587. /office365/{directory/security → security}/audit/compliance_dlp_exchange_audit_record.py +0 -0
  2588. /office365/{directory/security → security}/audit/compliance_dlp_exchange_classification_audit_record.py +0 -0
  2589. /office365/{directory/security → security}/audit/compliance_dlp_exchange_classification_cdp_record.py +0 -0
  2590. /office365/{directory/security → security}/audit/compliance_dlp_exchange_discovery_audit_record.py +0 -0
  2591. /office365/{directory/security → security}/audit/compliance_dlp_share_point_audit_record.py +0 -0
  2592. /office365/{directory/security → security}/audit/compliance_dlp_share_point_classification_audit_record.py +0 -0
  2593. /office365/{directory/security → security}/audit/compliance_dlp_share_point_classification_cdp_record.py +0 -0
  2594. /office365/{directory/security → security}/audit/compliance_dlp_share_point_classification_extended_audit_record.py +0 -0
  2595. /office365/{directory/security → security}/audit/compliance_exchange_ocr_audit_record.py +0 -0
  2596. /office365/{directory/security → security}/audit/compliance_manager_action_record.py +0 -0
  2597. /office365/{directory/security → security}/audit/compliance_policy_grading_share_point_audit_record.py +0 -0
  2598. /office365/{directory/security → security}/audit/compliance_settings_change_audit_record.py +0 -0
  2599. /office365/{directory/security → security}/audit/compliance_sit_grading_share_point_audit_record.py +0 -0
  2600. /office365/{directory/security → security}/audit/compliance_supervision_exchange_audit_record.py +0 -0
  2601. /office365/{directory/security → security}/audit/connected_ai_app_interaction_audit_record.py +0 -0
  2602. /office365/{directory/security → security}/audit/consumption_resource_audit_record.py +0 -0
  2603. /office365/{directory/security → security}/audit/content_store_metadata_record.py +0 -0
  2604. /office365/{directory/security → security}/audit/copilot_agent_management_audit_record.py +0 -0
  2605. /office365/{directory/security → security}/audit/copilot_for_security_logging_audit_record.py +0 -0
  2606. /office365/{directory/security → security}/audit/copilot_for_security_trigger_audit_record.py +0 -0
  2607. /office365/{directory/security → security}/audit/copilot_interaction_audit_record.py +0 -0
  2608. /office365/{directory/security → security}/audit/copilot_plugin_setting_audit_record.py +0 -0
  2609. /office365/{directory/security → security}/audit/copilot_prompt_book_setting_audit_record.py +0 -0
  2610. /office365/{directory/security → security}/audit/copilot_session_sharing_audit_record.py +0 -0
  2611. /office365/{directory/security → security}/audit/copilot_setting_audit_record.py +0 -0
  2612. /office365/{directory/security → security}/audit/copilot_workspace_setting_audit_record.py +0 -0
  2613. /office365/{directory/security → security}/audit/core_reporting_settings_audit_record.py +0 -0
  2614. /office365/{directory/security → security}/audit/critical_asset_management_classification_record.py +0 -0
  2615. /office365/{directory/security → security}/audit/crm_entity_operation_audit_record.py +0 -0
  2616. /office365/{directory/security → security}/audit/cross_tenant_access_policy_audit_record.py +0 -0
  2617. /office365/{directory/security → security}/audit/device_discovery_settings_authenticated_scans_record.py +0 -0
  2618. /office365/{directory/security → security}/audit/device_discovery_settings_exclusion_record.py +0 -0
  2619. /office365/{directory/security → security}/audit/device_discovery_settings_record.py +0 -0
  2620. /office365/{directory/security → security}/audit/discovery_audit_record.py +0 -0
  2621. /office365/{directory/security → security}/audit/dlp_endpoint_audit_record.py +0 -0
  2622. /office365/{directory/security → security}/audit/dlp_import_result_audit_record.py +0 -0
  2623. /office365/{directory/security → security}/audit/dragon_copilot_access_record.py +0 -0
  2624. /office365/{directory/security → security}/audit/dragon_copilot_admin_record.py +0 -0
  2625. /office365/{directory/security → security}/audit/dragon_copilot_clinical_data_record.py +0 -0
  2626. /office365/{directory/security → security}/audit/dragon_copilot_session_record.py +0 -0
  2627. /office365/{directory/security → security}/audit/dynamics365_business_central_audit_record.py +0 -0
  2628. /office365/{directory/security → security}/audit/ehr_connector_audit_base_record.py +0 -0
  2629. /office365/{directory/security → security}/audit/eop_submission_feed_entity_audit_record.py +0 -0
  2630. /office365/{directory/security → security}/audit/exchange_admin_audit_record.py +0 -0
  2631. /office365/{directory/security → security}/audit/exchange_aggregated_mailbox_audit_record.py +0 -0
  2632. /office365/{directory/security → security}/audit/exchange_aggregated_operation_record.py +0 -0
  2633. /office365/{directory/security → security}/audit/exchange_mailbox_audit_group_record.py +0 -0
  2634. /office365/{directory/security → security}/audit/exchange_mailbox_audit_record.py +0 -0
  2635. /office365/{directory/security → security}/audit/hosted_rpa_audit_record.py +0 -0
  2636. /office365/{directory/security → security}/audit/hr_signal_audit_record.py +0 -0
  2637. /office365/{directory/security → security}/audit/hygiene_event_record.py +0 -0
  2638. /office365/{directory/security → security}/audit/information_barrier_policy_application_audit_record.py +0 -0
  2639. /office365/{directory/security → security}/audit/information_worker_protection_audit_record.py +0 -0
  2640. /office365/{directory/security → security}/audit/insider_risk_scoped_user_insights_record.py +0 -0
  2641. /office365/{directory/security → security}/audit/insider_risk_scoped_users_record.py +0 -0
  2642. /office365/{directory/security → security}/audit/microsoft_stream_audit_record.py +0 -0
  2643. /office365/{directory/security → security}/audit/microsoft_teams_admin_audit_record.py +0 -0
  2644. /office365/{directory/security → security}/audit/microsoft_teams_analytics_audit_record.py +0 -0
  2645. /office365/{directory/security → security}/audit/microsoft_teams_audit_record.py +0 -0
  2646. /office365/{directory/security → security}/audit/microsoft_teams_device_audit_record.py +0 -0
  2647. /office365/{directory/security → security}/audit/microsoft_teams_retention_label_action_audit_record.py +0 -0
  2648. /office365/{directory/security → security}/audit/microsoft_teams_sensitivity_label_action_audit_record.py +0 -0
  2649. /office365/{directory/security → security}/audit/microsoft_teams_shifts_audit_record.py +0 -0
  2650. /office365/{directory/security → security}/audit/microsoft_teams_user_concern_audit_record.py +0 -0
  2651. /office365/{directory/security → security}/audit/multi_tenant_organization_join_request_transition_details.py +0 -0
  2652. /office365/{directory/security → security}/audit/multi_tenant_organization_member_transition_details.py +0 -0
  2653. /office365/{directory/security → security}/audit/whois_domain_status.py +0 -0
  2654. /office365/{directory/security → security}/audit/whois_history_record.py +0 -0
  2655. /office365/{directory/security → security}/authority_template.py +0 -0
  2656. /office365/{directory/security → security}/auto_auditing_configuration.py +0 -0
  2657. /office365/{directory/security → security}/autonomous_system.py +0 -0
  2658. /office365/{directory/security/incidents → security/cases}/__init__.py +0 -0
  2659. /office365/{directory/security → security}/cases/action.py +0 -0
  2660. /office365/{directory/security → security}/cases/additionaldataoptions.py +0 -0
  2661. /office365/{directory/security → security}/cases/additionaloptions.py +0 -0
  2662. /office365/{directory/security → security}/cases/exportcriteria.py +0 -0
  2663. /office365/{directory/security → security}/cases/exportfilestructure.py +0 -0
  2664. /office365/{directory/security → security}/cases/exportformat.py +0 -0
  2665. /office365/{directory/security → security}/cases/exportlocation.py +0 -0
  2666. /office365/{directory/security → security}/cases/exportoptions.py +0 -0
  2667. /office365/{directory/security → security}/cases/itemstoinclude.py +0 -0
  2668. /office365/{directory/security → security}/cases/operationstatus.py +0 -0
  2669. /office365/{directory/security → security}/cases/reviewsetsettings.py +0 -0
  2670. /office365/{directory/security → security}/cases/statisticsoptions.py +0 -0
  2671. /office365/{directory/security → security}/cases/status.py +0 -0
  2672. /office365/{directory/security → security}/cases/type.py +0 -0
  2673. /office365/{directory/security → security}/childselectability.py +0 -0
  2674. /office365/{directory/security → security}/citation_template.py +0 -0
  2675. /office365/{directory/security → security}/cloud_logon_request_evidence.py +0 -0
  2676. /office365/{directory/security → security}/cloudattachmentversion.py +0 -0
  2677. /office365/{directory/security/labels → security/collaboration}/__init__.py +0 -0
  2678. /office365/{directory/security → security}/collaboration/analyzed_email_authentication_detail.py +0 -0
  2679. /office365/{directory/security → security}/collaboration/analyzed_email_dlp_rule_info.py +0 -0
  2680. /office365/{directory/security → security}/collaboration/analyzed_email_exchange_transport_rule_info.py +0 -0
  2681. /office365/{directory/security → security}/collaboration/analyzed_email_recipient_detail.py +0 -0
  2682. /office365/{directory/security → security}/collaboration/analyzed_email_sender_detail.py +0 -0
  2683. /office365/{directory/security → security}/container_filter.py +0 -0
  2684. /office365/{directory/security → security}/container_registry_evidence.py +0 -0
  2685. /office365/{directory/security → security}/containerportprotocol.py +0 -0
  2686. /office365/{directory/security → security}/contentformat.py +0 -0
  2687. /office365/{directory/security → security}/contentprocessingerrortype.py +0 -0
  2688. /office365/{directory/security → security}/correlation_reason.py +0 -0
  2689. /office365/{directory/security → security}/cortana_briefing_audit_record.py +0 -0
  2690. /office365/{directory/security → security}/custom_security_attribute_comparison_operator.py +0 -0
  2691. /office365/{directory/security → security}/customer_key_service_encryption_audit_record.py +0 -0
  2692. /office365/{directory/security → security}/data_center_security_cmdlet_audit_record.py +0 -0
  2693. /office365/{directory/security → security}/data_governance_audit_record.py +0 -0
  2694. /office365/{directory/security → security}/data_insights_rest_api_audit_record.py +0 -0
  2695. /office365/{directory/security → security}/data_lake_export_operation_audit_record.py +0 -0
  2696. /office365/{directory/security → security}/data_set.py +0 -0
  2697. /office365/{directory/security → security}/data_share_operation_audit_record.py +0 -0
  2698. /office365/{directory/security/labels/retention → security/datasecurity}/__init__.py +0 -0
  2699. /office365/{directory/security → security}/datasecurity/classification_inner_error.py +0 -0
  2700. /office365/{directory/security → security}/datasecurity/custom_metadata_dictionary.py +0 -0
  2701. /office365/{directory/security → security}/datasecurity/dlp_action_info.py +0 -0
  2702. /office365/{directory/security → security}/datasecurity/integrated_application_metadata.py +0 -0
  2703. /office365/{directory/security/data_security_investigation_audit_record.py → security/datasecurity/investigation_audit_record.py} +0 -0
  2704. /office365/{directory/security → security}/datasecurity/policy_binding.py +0 -0
  2705. /office365/{directory/security → security}/datasecurity/policy_location.py +0 -0
  2706. /office365/{directory/security → security}/datasecurity/policy_location_application.py +0 -0
  2707. /office365/{directory/security → security}/datasecurity/policy_location_domain.py +0 -0
  2708. /office365/{directory/security → security}/datasecurity/policy_location_url.py +0 -0
  2709. /office365/{directory/security → security}/datasecurity/policy_user_scope.py +0 -0
  2710. /office365/{directory/security → security}/datasecurity/process_conversation_metadata.py +0 -0
  2711. /office365/{directory/security → security}/datasecurity/protected_content.py +0 -0
  2712. /office365/{directory/security → security}/default_audit_data.py +0 -0
  2713. /office365/{directory/security → security}/defender_case_management_audit_record.py +0 -0
  2714. /office365/{directory/security → security}/defender_preview_features_record.py +0 -0
  2715. /office365/{directory/security → security}/defender_security_for_ai_configuration_audit_record.py +0 -0
  2716. /office365/{directory/security → security}/delivery_action.py +0 -0
  2717. /office365/{directory/security → security}/delivery_location.py +0 -0
  2718. /office365/{directory/security → security}/department_template.py +0 -0
  2719. /office365/{directory/security → security}/deploy_feature_activity_record.py +0 -0
  2720. /office365/{directory/security → security}/deployment_access_key_type.py +0 -0
  2721. /office365/{directory/security → security}/detonation_behaviour_details.py +0 -0
  2722. /office365/{directory/security → security}/detonation_chain.py +0 -0
  2723. /office365/{directory/security → security}/detonation_observables.py +0 -0
  2724. /office365/{directory/security → security}/dictionary.py +0 -0
  2725. /office365/{directory/security → security}/dlp_sensitive_information_type_rule_package_cmdlet_record.py +0 -0
  2726. /office365/{directory/security → security}/dynamic_column_value.py +0 -0
  2727. /office365/{directory/security/scorecontrol → security/ediscovery}/__init__.py +0 -0
  2728. /office365/{directory/security/search → security/ediscovery/operations}/__init__.py +0 -0
  2729. /office365/{directory/security → security}/email_sender.py +0 -0
  2730. /office365/{directory/security → security}/event_source.py +0 -0
  2731. /office365/{directory/security → security}/export_file_metadata.py +0 -0
  2732. /office365/{directory/security → security}/fabric_audit_record.py +0 -0
  2733. /office365/{directory/security → security}/fabric_policy_record.py +0 -0
  2734. /office365/{directory/security → security}/file_details.py +0 -0
  2735. /office365/{directory/security → security}/file_plan_authority.py +0 -0
  2736. /office365/{directory/security → security}/file_plan_citation.py +0 -0
  2737. /office365/{directory/security → security}/file_plan_department.py +0 -0
  2738. /office365/{directory/security → security}/file_plan_descriptor_base.py +0 -0
  2739. /office365/{directory/security → security}/file_plan_descriptor_template.py +0 -0
  2740. /office365/{directory/security → security}/file_plan_reference.py +0 -0
  2741. /office365/{directory/security → security}/file_plan_reference_template.py +0 -0
  2742. /office365/{directory/security → security}/file_plan_subcategory.py +0 -0
  2743. /office365/{directory/security → security}/filehashalgorithm.py +0 -0
  2744. /office365/{directory/security → security}/filter_operand.py +0 -0
  2745. /office365/{directory/security → security}/geo_location.py +0 -0
  2746. /office365/{directory/security → security}/git_hub_organization_evidence.py +0 -0
  2747. /office365/{directory/security → security}/git_hub_repo_evidence.py +0 -0
  2748. /office365/{directory/security → security}/git_hub_user_evidence.py +0 -0
  2749. /office365/{directory/security → security}/group_filter.py +0 -0
  2750. /office365/{directory/security → security}/healthcare_signal_record.py +0 -0
  2751. /office365/{directory/security/securescores → security/healthissues}/__init__.py +0 -0
  2752. /office365/{directory/security → security}/healthissues/deploymentstatus.py +0 -0
  2753. /office365/{directory/security → security}/healthissues/sensorhealthstatus.py +0 -0
  2754. /office365/{directory/security → security}/healthissues/sensortype.py +0 -0
  2755. /office365/{directory/security → security}/healthissues/severity.py +0 -0
  2756. /office365/{directory/security → security}/healthissues/sourcetype.py +0 -0
  2757. /office365/{directory/security → security}/healthissues/status.py +0 -0
  2758. /office365/{directory/security → security}/healthissues/type.py +0 -0
  2759. /office365/{directory/security → security}/hunting_row_result.py +0 -0
  2760. /office365/{directory/security/subjectrightsrequests → security/incidents}/__init__.py +0 -0
  2761. /office365/{directory/security → security}/incidents/status.py +0 -0
  2762. /office365/{directory/security → security}/indicator_source.py +0 -0
  2763. /office365/{directory/security → security}/integrated_apps_app_admin_activity_audit_record.py +0 -0
  2764. /office365/{directory/security → security}/integrated_apps_app_settings_admin_activity_audit_record.py +0 -0
  2765. /office365/{directory/security → security}/intelligence_profile_indicator.py +0 -0
  2766. /office365/{directory/security → security}/intelligence_profile_kind.py +0 -0
  2767. /office365/{directory/security → security}/investigation_state.py +0 -0
  2768. /office365/{directory/security → security}/irm_activity_audit_trail_record.py +0 -0
  2769. /office365/{directory/security → security}/irm_user_defined_detection_record.py +0 -0
  2770. /office365/{directory/security → security}/kaizala_audit_record.py +0 -0
  2771. /office365/{directory/security/threatintelligence → security/labels}/__init__.py +0 -0
  2772. /office365/{directory/security/label_analytics_aggregate_audit_record.py → security/labels/analytics_aggregate_audit_record.py} +0 -0
  2773. /office365/{directory/security/label_content_explorer_audit_record.py → security/labels/content_explorer_audit_record.py} +0 -0
  2774. /office365/{directory/security/threatintelligence/hosts → security/labels/retention}/__init__.py +0 -0
  2775. /office365/{directory/security → security}/labels/retention/actionafterretentionperiod.py +0 -0
  2776. /office365/{directory/security → security}/labels/retention/behaviorduringretentionperiod.py +0 -0
  2777. /office365/{directory/security → security}/labels/retention/defaultrecordbehavior.py +0 -0
  2778. /office365/{directory/security → security}/labels/retention/disposition_review_stage.py +0 -0
  2779. /office365/{directory/security → security}/labels/retention/duration.py +0 -0
  2780. /office365/{directory/security → security}/labels/retention/trigger.py +0 -0
  2781. /office365/{directory/security → security}/large_content_metadata_audit_record.py +0 -0
  2782. /office365/{directory/security → security}/logged_on_user.py +0 -0
  2783. /office365/{directory/security → security}/m365_compliance_connector_audit_record.py +0 -0
  2784. /office365/{directory/security → security}/m365_search_sections_record.py +0 -0
  2785. /office365/{directory/security → security}/m365daad_audit_record.py +0 -0
  2786. /office365/{directory/security → security}/m365odsp_asset_metadata_record.py +0 -0
  2787. /office365/{directory/security → security}/mail_cluster_evidence.py +0 -0
  2788. /office365/{directory/security → security}/mail_submission_data.py +0 -0
  2789. /office365/{directory/security → security}/mailbox_configuration_type.py +0 -0
  2790. /office365/{directory/security → security}/managed_services_audit_record.py +0 -0
  2791. /office365/{directory/security → security}/managed_tenants_audit_record.py +0 -0
  2792. /office365/{directory/security → security}/mapg_alerts_audit_record.py +0 -0
  2793. /office365/{directory/security → security}/mapg_onboard_audit_record.py +0 -0
  2794. /office365/{directory/security → security}/mapg_policy_audit_record.py +0 -0
  2795. /office365/{directory/security → security}/mapg_remediation_audit_record.py +0 -0
  2796. /office365/{directory/security → security}/mcas_alerts_audit_record.py +0 -0
  2797. /office365/{directory/security → security}/mda_audit_record.py +0 -0
  2798. /office365/{directory/security → security}/mda_data_security_signal_record.py +0 -0
  2799. /office365/{directory/security → security}/mdash_audit_record.py +0 -0
  2800. /office365/{directory/security → security}/mdatp_audit_record.py +0 -0
  2801. /office365/{directory/security → security}/mdc_events_record.py +0 -0
  2802. /office365/{directory/security → security}/mdi_audit_record.py +0 -0
  2803. /office365/{directory/security → security}/merge_response.py +0 -0
  2804. /office365/{directory/security → security}/mesh_worlds_audit_record.py +0 -0
  2805. /office365/{directory/security → security}/microsoft365_backup_backup_item_audit_record.py +0 -0
  2806. /office365/{directory/security → security}/microsoft365_backup_backup_policy_audit_record.py +0 -0
  2807. /office365/{directory/security → security}/microsoft365_backup_granular_browse_task_audit_record.py +0 -0
  2808. /office365/{directory/security → security}/microsoft365_backup_restore_item_audit_record.py +0 -0
  2809. /office365/{directory/security → security}/microsoft365_backup_restore_task_audit_record.py +0 -0
  2810. /office365/{directory/security → security}/microsoft365_copilot_scheduled_prompt_audit_record.py +0 -0
  2811. /office365/{directory/security → security}/microsoft_defender_experts_xdr_audit_record.py +0 -0
  2812. /office365/{directory/security → security}/microsoft_flow_audit_record.py +0 -0
  2813. /office365/{directory/security → security}/microsoft_forms_audit_record.py +0 -0
  2814. /office365/{directory/security → security}/microsoft_graph_data_connect_consent.py +0 -0
  2815. /office365/{directory/security → security}/microsoft_graph_data_connect_operation.py +0 -0
  2816. /office365/{directory/security → security}/microsoft_purview_data_catalog_operation_record.py +0 -0
  2817. /office365/{directory/security → security}/microsoft_purview_data_map_operation_record.py +0 -0
  2818. /office365/{directory/security → security}/microsoft_purview_metadata_policy_operation_record.py +0 -0
  2819. /office365/{directory/security → security}/microsoft_purview_policy_operation_record.py +0 -0
  2820. /office365/{directory/security → security}/microsoft_purview_privacy_audit_event.py +0 -0
  2821. /office365/{directory/security → security}/microsoft_purview_unified_catalog_operation_record.py +0 -0
  2822. /office365/{directory/security → security}/mip_auto_label_exchange_item_audit_record.py +0 -0
  2823. /office365/{directory/security → security}/mip_auto_label_progress_feedback_audit_record.py +0 -0
  2824. /office365/{directory/security → security}/mip_auto_label_share_point_item_audit_record.py +0 -0
  2825. /office365/{directory/security → security}/mip_auto_label_share_point_policy_location_audit_record.py +0 -0
  2826. /office365/{directory/security → security}/mip_auto_label_simulation_share_point_completion_record.py +0 -0
  2827. /office365/{directory/security → security}/mip_auto_label_simulation_share_point_progress_record.py +0 -0
  2828. /office365/{directory/security → security}/mip_auto_label_simulation_statistics_record.py +0 -0
  2829. /office365/{directory/security → security}/mip_exact_data_match_audit_record.py +0 -0
  2830. /office365/{directory/security → security}/mip_label_analytics_audit_record.py +0 -0
  2831. /office365/{directory/security → security}/mip_label_audit_record.py +0 -0
  2832. /office365/{directory/security → security}/mos_agent_info_record.py +0 -0
  2833. /office365/{directory/security → security}/mos_agent_info_record_v2.py +0 -0
  2834. /office365/{directory/security → security}/ms365d_custom_detection_audit_record.py +0 -0
  2835. /office365/{directory/security → security}/ms365d_incident_audit_record.py +0 -0
  2836. /office365/{directory/security → security}/ms365d_suppression_rule_audit_record.py +0 -0
  2837. /office365/{directory/security → security}/msde_custom_collection_audit_record.py +0 -0
  2838. /office365/{directory/security → security}/msde_general_settings_audit_record.py +0 -0
  2839. /office365/{directory/security → security}/msde_indicators_settings_audit_record.py +0 -0
  2840. /office365/{directory/security → security}/msde_response_actions_audit_record.py +0 -0
  2841. /office365/{directory/security → security}/msde_roles_settings_audit_record.py +0 -0
  2842. /office365/{directory/security → security}/msp_vector_search_content_metadata_audit_record.py +0 -0
  2843. /office365/{directory/security → security}/mstic_nation_state_notification_record.py +0 -0
  2844. /office365/{directory/security → security}/multi_stage_disposition_audit_record.py +0 -0
  2845. /office365/{directory/security → security}/my_analytics_settings_audit_record.py +0 -0
  2846. /office365/{directory/security → security}/network_adapter.py +0 -0
  2847. /office365/{directory/security → security}/noisy_alert_policy_audit_record.py +0 -0
  2848. /office365/{directory/security → security}/oauth_application_evidence.py +0 -0
  2849. /office365/{directory/security → security}/object_definition_metadata_entry.py +0 -0
  2850. /office365/{directory/security → security}/object_mapping_metadata_entry.py +0 -0
  2851. /office365/{directory/security → security}/ocr_settings.py +0 -0
  2852. /office365/{directory/security → security}/office_native_audit_record.py +0 -0
  2853. /office365/{directory/security → security}/ome_portal_audit_record.py +0 -0
  2854. /office365/{directory/security → security}/on_demand_share_point_classification_audit_record.py +0 -0
  2855. /office365/{directory/security → security}/on_premises_file_share_scanner_dlp_audit_record.py +0 -0
  2856. /office365/{directory/security → security}/on_premises_share_point_scanner_dlp_audit_record.py +0 -0
  2857. /office365/{directory/security → security}/onboarding_status.py +0 -0
  2858. /office365/{directory/security → security}/one_drive_audit_record.py +0 -0
  2859. /office365/{directory/security → security}/organizational_data_in_m365_audit_record.py +0 -0
  2860. /office365/{directory/security → security}/outlook_copilot_automation_audit_record.py +0 -0
  2861. /office365/{directory/security → security}/owa_get_access_token_for_resource_audit_record.py +0 -0
  2862. /office365/{directory/security → security}/p4_ai_risk_score_record.py +0 -0
  2863. /office365/{directory/security → security}/p4ai_assessment_category_record.py +0 -0
  2864. /office365/{directory/security → security}/p4ai_assessment_fabric_scanner_record.py +0 -0
  2865. /office365/{directory/security → security}/p4ai_assessment_location_result_record.py +0 -0
  2866. /office365/{directory/security → security}/p4ai_assessment_record.py +0 -0
  2867. /office365/{directory/security → security}/people_admin_settings_audit_record.py +0 -0
  2868. /office365/{directory/security → security}/physical_badging_signal_audit_record.py +0 -0
  2869. /office365/{directory/security → security}/places_directory_audit_record.py +0 -0
  2870. /office365/{directory/security → security}/planner_chat_message_audit_record.py +0 -0
  2871. /office365/{directory/security → security}/planner_chat_message_list_audit_record.py +0 -0
  2872. /office365/{directory/security → security}/planner_copy_plan_audit_record.py +0 -0
  2873. /office365/{directory/security → security}/planner_goal_audit_record.py +0 -0
  2874. /office365/{directory/security → security}/planner_goal_list_audit_record.py +0 -0
  2875. /office365/{directory/security → security}/planner_plan_audit_record.py +0 -0
  2876. /office365/{directory/security → security}/planner_plan_list_audit_record.py +0 -0
  2877. /office365/{directory/security → security}/planner_plan_sensitivity_label_audit_record.py +0 -0
  2878. /office365/{directory/security → security}/planner_roster_audit_record.py +0 -0
  2879. /office365/{directory/security → security}/planner_roster_sensitivity_label_audit_record.py +0 -0
  2880. /office365/{directory/security → security}/planner_task_audit_record.py +0 -0
  2881. /office365/{directory/security → security}/planner_task_list_audit_record.py +0 -0
  2882. /office365/{directory/security → security}/planner_tenant_settings_audit_record.py +0 -0
  2883. /office365/{directory/security → security}/policy_config_change_audit_record.py +0 -0
  2884. /office365/{directory/security → security}/policypivotproperty.py +0 -0
  2885. /office365/{directory/security → security}/power_apps_audit_app_record.py +0 -0
  2886. /office365/{directory/security → security}/power_apps_audit_plan_record.py +0 -0
  2887. /office365/{directory/security → security}/power_apps_audit_resource_record.py +0 -0
  2888. /office365/{directory/security → security}/power_bi_audit_record.py +0 -0
  2889. /office365/{directory/security → security}/power_bi_dlp_audit_record.py +0 -0
  2890. /office365/{directory/security → security}/power_pages_site_audit_record.py +0 -0
  2891. /office365/{directory/security → security}/power_platform_admin_dlp_audit_record.py +0 -0
  2892. /office365/{directory/security → security}/power_platform_admin_environment_audit_record.py +0 -0
  2893. /office365/{directory/security → security}/power_platform_administrator_activity_record.py +0 -0
  2894. /office365/{directory/security → security}/power_platform_lockbox_resource_access_request_audit_record.py +0 -0
  2895. /office365/{directory/security → security}/power_platform_lockbox_resource_command_audit_record.py +0 -0
  2896. /office365/{directory/security → security}/power_platform_service_activity_audit_record.py +0 -0
  2897. /office365/{directory/security → security}/power_platform_tenant_isolation_record.py +0 -0
  2898. /office365/{directory/security → security}/priva_privacy_assessment_operation_record.py +0 -0
  2899. /office365/{directory/security → security}/priva_privacy_consent_operation_record.py +0 -0
  2900. /office365/{directory/security → security}/privacy_data_match_audit_record.py +0 -0
  2901. /office365/{directory/security → security}/privacy_data_minimization_record.py +0 -0
  2902. /office365/{directory/security → security}/privacy_digest_email_record.py +0 -0
  2903. /office365/{directory/security → security}/privacy_open_access_audit_record.py +0 -0
  2904. /office365/{directory/security → security}/privacy_portal_audit_record.py +0 -0
  2905. /office365/{directory/security → security}/privacy_remediation_action_record.py +0 -0
  2906. /office365/{directory/security → security}/privacy_remediation_record.py +0 -0
  2907. /office365/{directory/security → security}/project_audit_record.py +0 -0
  2908. /office365/{directory/security → security}/project_for_the_web_assigned_to_me_settings_audit_record.py +0 -0
  2909. /office365/{directory/security → security}/project_for_the_web_project_audit_record.py +0 -0
  2910. /office365/{directory/security → security}/project_for_the_web_project_settings_audit_record.py +0 -0
  2911. /office365/{directory/security → security}/project_for_the_web_roadmap_audit_record.py +0 -0
  2912. /office365/{directory/security → security}/project_for_the_web_roadmap_item_audit_record.py +0 -0
  2913. /office365/{directory/security → security}/project_for_the_web_roadmap_settings_audit_record.py +0 -0
  2914. /office365/{directory/security → security}/project_for_the_web_task_audit_record.py +0 -0
  2915. /office365/{directory/security → security}/protectionscopestate.py +0 -0
  2916. /office365/{directory/security → security}/protocol_type.py +0 -0
  2917. /office365/{directory/security → security}/public_error_response.py +0 -0
  2918. /office365/{directory/security → security}/public_folder_audit_record.py +0 -0
  2919. /office365/{directory/security → security}/purgeareas.py +0 -0
  2920. /office365/{directory/security → security}/purgetype.py +0 -0
  2921. /office365/{directory/security → security}/purview_insider_risk_alerts_record.py +0 -0
  2922. /office365/{directory/security → security}/purview_insider_risk_cases_record.py +0 -0
  2923. /office365/{directory/security → security}/purview_mc_recommendation_record.py +0 -0
  2924. /office365/{directory/security → security}/purview_posture_agent_audit_record.py +0 -0
  2925. /office365/{directory/security → security}/quarantine_audit_record.py +0 -0
  2926. /office365/{directory/security → security}/query_type.py +0 -0
  2927. /office365/{directory/security → security}/recipient_type.py +0 -0
  2928. /office365/{directory/security → security}/records_management_audit_record.py +0 -0
  2929. /office365/{directory/security → security}/redundancy_detection_settings.py +0 -0
  2930. /office365/{directory/security → security}/referenced_object.py +0 -0
  2931. /office365/{directory/security → security}/registry_key_evidence.py +0 -0
  2932. /office365/{directory/security → security}/registry_value_evidence.py +0 -0
  2933. /office365/{directory/security → security}/remediation_action.py +0 -0
  2934. /office365/{directory/security → security}/remediation_severity.py +0 -0
  2935. /office365/{directory/security → security}/report_file_metadata.py +0 -0
  2936. /office365/{directory/security → security}/report_submission.py +0 -0
  2937. /office365/{directory/security → security}/report_submission_result_detail.py +0 -0
  2938. /office365/{directory/security → security}/resource_access_event.py +0 -0
  2939. /office365/{directory/security → security}/restricted_mode_audit_record.py +0 -0
  2940. /office365/{directory/security → security}/restrictionaction.py +0 -0
  2941. /office365/{directory/security → security}/retention_duration_forever.py +0 -0
  2942. /office365/{directory/security → security}/retention_policy_audit_record.py +0 -0
  2943. /office365/{directory/security → security}/riskscore.py +0 -0
  2944. /office365/{directory/security → security}/rti_operations_agent_audit_record.py +0 -0
  2945. /office365/{directory/security → security}/sbp_configuration_event_record.py +0 -0
  2946. /office365/{directory/security → security}/sbp_usage_event_record.py +0 -0
  2947. /office365/{directory/security → security}/score_evidence.py +0 -0
  2948. /office365/{directory/security → security}/score_platform_generic_audit_record.py +0 -0
  2949. /office365/{directory/security/threatintelligence/whoisrecords → security/scorecontrol}/__init__.py +0 -0
  2950. /office365/{directory/security → security}/script_run_audit_record.py +0 -0
  2951. /office365/{directory/security/triggers → security/search}/__init__.py +0 -0
  2952. /office365/{directory/security/search_audit_record.py → security/search/audit_record.py} +0 -0
  2953. /office365/{directory/security → security}/search/datasourcecontainerstatus.py +0 -0
  2954. /office365/{directory/security → security}/search/datasourceholdstatus.py +0 -0
  2955. /office365/{directory/security → security}/search/datasourcescopes.py +0 -0
  2956. /office365/{directory/security → security}/search/documentversion.py +0 -0
  2957. /office365/{directory/security → security}/search.py +0 -0
  2958. /office365/{directory/security/triggertypes → security/securescores}/__init__.py +0 -0
  2959. /office365/{directory/security → security}/security_compliance_alert_record.py +0 -0
  2960. /office365/{directory/security → security}/security_compliance_center_eop_cmdlet_audit_record.py +0 -0
  2961. /office365/{directory/security → security}/security_compliance_insights_audit_record.py +0 -0
  2962. /office365/{directory/security → security}/security_compliance_rbac_audit_record.py +0 -0
  2963. /office365/{directory/security → security}/security_compliance_user_change_audit_record.py +0 -0
  2964. /office365/{directory/security → security}/security_copilot_identity_management_audit_record.py +0 -0
  2965. /office365/{directory/security → security}/security_development_lifecycle_ai_log_audit_record.py +0 -0
  2966. /office365/{directory/security → security}/security_group_evidence.py +0 -0
  2967. /office365/{directory/security → security}/sensitive_info_remediation_agent_data_record.py +0 -0
  2968. /office365/{directory/security → security}/sensitivity_label_action_audit_record.py +0 -0
  2969. /office365/{directory/security → security}/sensitivity_label_policy_match_audit_record.py +0 -0
  2970. /office365/{directory/security → security}/sensitivity_labeled_file_action_audit_record.py +0 -0
  2971. /office365/{directory/security → security}/sensor_candidate.py +0 -0
  2972. /office365/{directory/security → security}/sensor_candidate_activation_mode.py +0 -0
  2973. /office365/{directory/security → security}/sensor_deployment_package.py +0 -0
  2974. /office365/{directory/security → security}/sentinel_ai_tool_audit_record.py +0 -0
  2975. /office365/{directory/security → security}/sentinel_graph_audit_record.py +0 -0
  2976. /office365/{directory/security → security}/sentinel_job_audit_record.py +0 -0
  2977. /office365/{directory/security → security}/sentinel_kql_on_lake_audit_record.py +0 -0
  2978. /office365/{directory/security → security}/sentinel_lake_data_onboarding_audit_record.py +0 -0
  2979. /office365/{directory/security → security}/sentinel_lake_encryption_audit_record.py +0 -0
  2980. /office365/{directory/security → security}/sentinel_lake_onboarding_audit_record.py +0 -0
  2981. /office365/{directory/security → security}/sentinel_notebook_on_lake_audit_record.py +0 -0
  2982. /office365/{directory/security → security}/sentinel_package_audit_record.py +0 -0
  2983. /office365/{directory/security → security}/service_principal_type.py +0 -0
  2984. /office365/{directory/security → security}/service_source.py +0 -0
  2985. /office365/{directory/security → security}/share_point_app_permission_operation_audit_record.py +0 -0
  2986. /office365/{directory/security → security}/share_point_audit_record.py +0 -0
  2987. /office365/{directory/security → security}/share_point_comment_operation_audit_record.py +0 -0
  2988. /office365/{directory/security → security}/share_point_content_security_policy_audit_record.py +0 -0
  2989. /office365/{directory/security → security}/share_point_content_type_operation_audit_record.py +0 -0
  2990. /office365/{directory/security → security}/share_point_e_signature_audit_record.py +0 -0
  2991. /office365/{directory/security → security}/share_point_field_operation_audit_record.py +0 -0
  2992. /office365/{directory/security → security}/share_point_file_operation_audit_record.py +0 -0
  2993. /office365/{directory/security → security}/share_point_list_item_operation_audit_record.py +0 -0
  2994. /office365/{directory/security → security}/share_point_list_operation_audit_record.py +0 -0
  2995. /office365/{directory/security → security}/share_point_sharing_operation_audit_record.py +0 -0
  2996. /office365/{directory/security → security}/single_property_schema.py +0 -0
  2997. /office365/{directory/security → security}/site_source.py +0 -0
  2998. /office365/{directory/security → security}/skype_for_business_cmdlets_audit_record.py +0 -0
  2999. /office365/{directory/security → security}/skype_for_business_pstn_usage_audit_record.py +0 -0
  3000. /office365/{directory/security → security}/skype_for_business_users_blocked_audit_record.py +0 -0
  3001. /office365/{directory/security → security}/sonar_detonation_content_metadata.py +0 -0
  3002. /office365/{directory/security → security}/sonar_detonation_entity_audit_record.py +0 -0
  3003. /office365/{directory/security → security}/sonar_file_detonation_entity_audit_record.py +0 -0
  3004. /office365/{directory/security → security}/sonar_submission_entity_audit_record.py +0 -0
  3005. /office365/{directory/security → security}/sonar_url_detonation_entity_audit_record.py +0 -0
  3006. /office365/{directory/security → security}/spark_core_custom_live_pool_record.py +0 -0
  3007. /office365/{directory/security → security}/stream.py +0 -0
  3008. /office365/{directory/security → security}/string_key_long_value_pair.py +0 -0
  3009. /office365/{directory/security → security}/string_key_object_value_pair.py +0 -0
  3010. /office365/{directory/security → security}/string_key_string_value_pair.py +0 -0
  3011. /office365/{directory/security → security}/string_value_dictionary.py +0 -0
  3012. /office365/{directory/security → security}/subcategory_template.py +0 -0
  3013. /office365/{intune/devices/configurations/windows/10 → security/subjectrightsrequests}/__init__.py +0 -0
  3014. /office365/{directory/security → security}/subjectrightsrequests/all_mailbox_location.py +0 -0
  3015. /office365/{directory/security → security}/subjectrightsrequests/all_site_location.py +0 -0
  3016. /office365/{directory/security → security}/subjectrightsrequests/data_subject.py +0 -0
  3017. /office365/{directory/security → security}/subjectrightsrequests/detail.py +0 -0
  3018. /office365/{directory/security → security}/subjectrightsrequests/enumerated_mailbox_location.py +0 -0
  3019. /office365/{directory/security → security}/subjectrightsrequests/enumerated_site_location.py +0 -0
  3020. /office365/{directory/security → security}/subjectrightsrequests/history.py +0 -0
  3021. /office365/{directory/security → security}/subjectrightsrequests/mailbox_location.py +0 -0
  3022. /office365/{directory/security → security}/subjectrightsrequests/site_location.py +0 -0
  3023. /office365/{directory/security → security}/subjectrightsrequests/stage_detail.py +0 -0
  3024. /office365/{directory/security → security}/submission_entity_audit_record.py +0 -0
  3025. /office365/{directory/security → security}/submission_mail_evidence.py +0 -0
  3026. /office365/{directory/security → security}/supervisory_review_day_x_insights_audit_record.py +0 -0
  3027. /office365/{directory/security → security}/synthetic_probe_audit_record.py +0 -0
  3028. /office365/{directory/security → security}/tag.py +0 -0
  3029. /office365/{directory/security → security}/team_copilot_interaction_audit_record.py +0 -0
  3030. /office365/{directory/security → security}/teams_delivery_location.py +0 -0
  3031. /office365/{directory/security → security}/teams_easy_approvals_audit_record.py +0 -0
  3032. /office365/{directory/security → security}/teams_eval_data_hub_admin_operation_audit_record.py +0 -0
  3033. /office365/{directory/security → security}/teams_eval_data_hub_data_access_audit_record.py +0 -0
  3034. /office365/{directory/security → security}/teams_eval_data_hub_permission_change_audit_record.py +0 -0
  3035. /office365/{directory/security → security}/teams_healthcare_audit_record.py +0 -0
  3036. /office365/{directory/security → security}/teams_message_delivery_action.py +0 -0
  3037. /office365/{directory/security → security}/teams_updates_audit_record.py +0 -0
  3038. /office365/{directory/security → security}/tenant_allow_block_list_audit_record.py +0 -0
  3039. /office365/{directory/security → security}/threat_detection_detail.py +0 -0
  3040. /office365/{directory/security → security}/threat_finder_audit_record.py +0 -0
  3041. /office365/{directory/security → security}/threat_type.py +0 -0
  3042. /office365/{sharepoint/publishing/pages/3d → security/threatintelligence}/__init__.py +0 -0
  3043. /office365/{directory/security → security}/threatintelligence/article_indicator.py +0 -0
  3044. /office365/{directory/security/threat_intelligence_atp_content_data.py → security/threatintelligence/atp_content_data.py} +0 -0
  3045. /office365/{directory/security/threat_intelligence_export_audit_record.py → security/threatintelligence/export_audit_record.py} +0 -0
  3046. /office365/{directory/security → security}/threatintelligence/host_port_banner.py +0 -0
  3047. /office365/{directory/security → security}/threatintelligence/host_port_protocol.py +0 -0
  3048. /office365/{directory/security → security}/threatintelligence/host_port_status.py +0 -0
  3049. /office365/{directory/security → security}/threatintelligence/host_reputation_classification.py +0 -0
  3050. /office365/{directory/security → security}/threatintelligence/host_reputation_rule_severity.py +0 -0
  3051. /office365/{directory/security → security}/threatintelligence/hostname.py +0 -0
  3052. /office365/{directory/security/threat_intelligence_mail_data.py → security/threatintelligence/mail_data.py} +0 -0
  3053. /office365/{directory/security/threat_intelligence_object_audit_record.py → security/threatintelligence/object_audit_record.py} +0 -0
  3054. /office365/{directory/security/threat_intelligence_url_click_data.py → security/threatintelligence/url_click_data.py} +0 -0
  3055. /office365/{directory/security → security}/timeline_event_type.py +0 -0
  3056. /office365/{directory/security → security}/todo_audit_record.py +0 -0
  3057. /office365/{directory/security → security}/topic_modeling_settings.py +0 -0
  3058. /office365/{directory/security → security}/trainable_classifier_audit_record.py +0 -0
  3059. /office365/{directory/security → security}/triggers/eventpropagationstatus.py +0 -0
  3060. /office365/{directory/security → security}/triggers/eventstatustype.py +0 -0
  3061. /office365/{directory/security → security}/triggertypes/event_type.py +0 -0
  3062. /office365/{directory/security → security}/uam_operation_audit_record.py +0 -0
  3063. /office365/{directory/security → security}/unclassified_artifact.py +0 -0
  3064. /office365/{directory/security → security}/unified_group_audit_record.py +0 -0
  3065. /office365/{directory/security → security}/unified_simulation_matched_item_audit_record.py +0 -0
  3066. /office365/{directory/security → security}/unified_simulation_summary_audit_record.py +0 -0
  3067. /office365/{directory/security → security}/universal_print_management_audit_record.py +0 -0
  3068. /office365/{directory/security → security}/universal_print_print_job_audit_record.py +0 -0
  3069. /office365/{directory/security → security}/urbac_assignment_audit_record.py +0 -0
  3070. /office365/{directory/security → security}/urbac_enable_state_audit_record.py +0 -0
  3071. /office365/{directory/security → security}/urbac_role_audit_record.py +0 -0
  3072. /office365/{directory/security → security}/url_evidence.py +0 -0
  3073. /office365/{directory/security → security}/user_training_audit_record.py +0 -0
  3074. /office365/{directory/security → security}/useractivitytype.py +0 -0
  3075. /office365/{directory/security → security}/useractivitytypes.py +0 -0
  3076. /office365/{directory/security → security}/userscopetype.py +0 -0
  3077. /office365/{directory/security → security}/usx_workspace_onboarding_audit_record.py +0 -0
  3078. /office365/{directory/security → security}/verdict_category.py +0 -0
  3079. /office365/{directory/security → security}/vfam_create_policy_audit_record.py +0 -0
  3080. /office365/{directory/security → security}/vfam_delete_policy_audit_record.py +0 -0
  3081. /office365/{directory/security → security}/vfam_update_policy_audit_record.py +0 -0
  3082. /office365/{directory/security → security}/viva_amplify_audit_record.py +0 -0
  3083. /office365/{directory/security → security}/viva_engage_events_audit_record.py +0 -0
  3084. /office365/{directory/security → security}/viva_engage_network_association_audit_record.py +0 -0
  3085. /office365/{directory/security → security}/viva_engage_segment_audit_record.py +0 -0
  3086. /office365/{directory/security → security}/viva_glint_advanced_configuration_audit_record.py +0 -0
  3087. /office365/{directory/security → security}/viva_glint_agentic_campaign_audit_record.py +0 -0
  3088. /office365/{directory/security → security}/viva_glint_feedback_program_audit_record.py +0 -0
  3089. /office365/{directory/security → security}/viva_glint_organizational_data_audit_record.py +0 -0
  3090. /office365/{directory/security → security}/viva_glint_pulse_program_audit_record.py +0 -0
  3091. /office365/{directory/security → security}/viva_glint_pulse_program_respondent_rate_audit_record.py +0 -0
  3092. /office365/{directory/security → security}/viva_glint_question_audit_record.py +0 -0
  3093. /office365/{directory/security → security}/viva_glint_role_audit_record.py +0 -0
  3094. /office365/{directory/security → security}/viva_glint_rubicon_audit_record.py +0 -0
  3095. /office365/{directory/security → security}/viva_glint_support_access_audit_record.py +0 -0
  3096. /office365/{directory/security → security}/viva_glint_system_audit_record.py +0 -0
  3097. /office365/{directory/security → security}/viva_glint_user_audit_record.py +0 -0
  3098. /office365/{directory/security → security}/viva_glint_user_group_audit_record.py +0 -0
  3099. /office365/{directory/security → security}/viva_goals_audit_record.py +0 -0
  3100. /office365/{directory/security → security}/viva_learning_admin_audit_record.py +0 -0
  3101. /office365/{directory/security → security}/viva_learning_audit_record.py +0 -0
  3102. /office365/{directory/security → security}/viva_pulse_admin_audit_record.py +0 -0
  3103. /office365/{directory/security → security}/viva_pulse_organizer_audit_record.py +0 -0
  3104. /office365/{directory/security → security}/viva_pulse_report_audit_record.py +0 -0
  3105. /office365/{directory/security → security}/viva_pulse_response_audit_record.py +0 -0
  3106. /office365/{directory/security → security}/vm_cloud_provider.py +0 -0
  3107. /office365/{directory/security → security}/vulnerability_component.py +0 -0
  3108. /office365/{directory/security → security}/vulnerability_severity.py +0 -0
  3109. /office365/{directory/security → security}/wdatp_alerts_audit_record.py +0 -0
  3110. /office365/{directory/security → security}/web_content_filtering_audit_record.py +0 -0
  3111. /office365/{directory/security → security}/windows365_customer_lockbox_audit_record.py +0 -0
  3112. /office365/{directory/security → security}/workplace_analytics_audit_record.py +0 -0
  3113. /office365/{directory/security → security}/yammer_audit_record.py +0 -0
  3114. /office365/{directory/security → security}/yammer_user_hiding_audit_record.py +0 -0
  3115. /office365/sharepoint/publishing/pages/{3d → _3d}/types.py +0 -0
  3116. /office365/{intune/print → todo/tasks}/taskstatus.py +0 -0
  3117. {office365_rest_python_client-3.1.0.dist-info → office365_rest_python_client-3.3.0.dist-info}/WHEEL +0 -0
@@ -12,50 +12,532 @@ from __future__ import annotations
12
12
 
13
13
  import hashlib
14
14
  import io
15
+ import json
15
16
  from collections.abc import Callable
16
- from typing import TYPE_CHECKING, cast
17
+ from datetime import datetime, timezone
18
+ from typing import TYPE_CHECKING, Any, cast
19
+
20
+ from typing_extensions import TypeAlias
17
21
 
18
- from office365.migration._util import emit_progress, record_to_json
19
22
  from office365.migration.adapters import MigrationProgress
20
- from office365.migration.base import MigrationItem
23
+ from office365.migration.base import (
24
+ MigrationItem,
25
+ PermissionEntry,
26
+ Principal,
27
+ conflict_to_on_conflict,
28
+ normalize_puid,
29
+ )
30
+ from office365.migration.sharepoint.structure import normalize_guid
21
31
  from office365.migration.sharepoint.transfer import Failure
32
+ from office365.runtime.converters.records import records_from_items
33
+ from office365.runtime.converters.scalars import iso_or_none, parse_datetime, parse_int
34
+ from office365.runtime.limits import DEFAULT_BATCH_SIZE
35
+ from office365.runtime.operations import emit_progress
36
+ from office365.sharepoint.fields.builtin_field_name import SYSTEM_FIELD_NAMES
37
+ from office365.sharepoint.fields.user_value import FieldUserValue
38
+ from office365.sharepoint.principal.type import PrincipalType
22
39
 
23
40
  if TYPE_CHECKING:
41
+ from office365.migration.map import ContentTypeMap
24
42
  from office365.sharepoint.files.file import File
25
43
  from office365.sharepoint.folders.folder import Folder
26
44
  from office365.sharepoint.lists.list import List as SPList
45
+ from office365.sharepoint.permissions.roles.definitions.definition import RoleDefinition
27
46
 
28
47
  _TAXONOMY_FIELD_TYPES = {"TaxonomyFieldType", "TaxonomyFieldTypeMulti"}
29
48
 
30
- # Read-only bookkeeping columns that add no content and can require extra
31
- # permissions to project; never part of the fallback select.
32
- _SYSTEM_INTERNAL_NAMES = {
33
- "ContentTypeId",
34
- "ContentType",
35
- "Created",
36
- "Modified",
37
- "Author",
38
- "Editor",
49
+
50
+ def _cloned_context(obj):
51
+ """A fresh ``ClientContext`` clone for ``obj`` (same auth + transport, own queue)."""
52
+ ctx = obj.context
53
+ return ctx.clone(ctx.base_url)
54
+
55
+
56
+ def _cloned_list(sp_list: "SPList", context=None) -> "SPList":
57
+ """The same list, addressed by id and loaded on ``context`` (or a clone of it)."""
58
+ list_id = sp_list.id
59
+ if not list_id:
60
+ raise ValueError("cannot rebind a list that was never loaded")
61
+ ctx = context if context is not None else _cloned_context(sp_list)
62
+ return ctx.web.lists.get_by_id(list_id).get().execute_query()
63
+
64
+
65
+ def _cloned_folder(folder: "Folder", context=None) -> "Folder":
66
+ """The same folder, addressed by server-relative path and loaded on ``context``."""
67
+ server_relative_url = folder.server_relative_url
68
+ if not server_relative_url:
69
+ raise ValueError("cannot rebind a folder that was never loaded")
70
+ ctx = context if context is not None else _cloned_context(folder)
71
+ return ctx.web.get_folder_by_server_relative_path(server_relative_url).get().execute_query()
72
+
73
+
74
+ #: The target's typed columns: ``(lookup: name -> referenced list id, user names,
75
+ #: multi-lookup: name -> referenced list id, multi-user names, taxonomy:
76
+ #: name -> (allows many, hidden note field internal name), multi-choice names)``.
77
+ _TypedColumns: TypeAlias = (
78
+ "tuple[dict[str, str], set[str], dict[str, str], set[str], dict[str, tuple[bool, str | None]], set[str]]"
79
+ )
80
+
81
+ # Always-projected system metadata (reliable author/editor identity).
82
+ _METADATA_SELECT = ["AuthorId", "EditorId", "HasUniqueRoleAssignments"]
83
+ #: Projected system metadata that is read-only and must not be written back.
84
+ _NON_WRITABLE_SELECT = frozenset({"HasUniqueRoleAssignments"})
85
+
86
+ #: Navigation properties a ``*`` read returns that carry no scalar content and can
87
+ #: never be written back; they are dropped silently. A genuine typed value we
88
+ #: cannot remap (a lookup/person column) is still surfaced as a warning.
89
+ _NAVIGATION_SELECT = frozenset(
90
+ {
91
+ "ParentList",
92
+ "ContentType",
93
+ "Folder",
94
+ "File",
95
+ "FieldValuesAsHtml",
96
+ "FieldValuesAsText",
97
+ "FieldValuesForEdit",
98
+ }
99
+ )
100
+
101
+ #: Marker column added to a migrated list recording each item's source id. It makes
102
+ #: a re-run idempotent and lets post-run verification pair source and target items.
103
+ DEFAULT_LIST_IDENTITY_FIELD = "MigrationSourceId"
104
+ # Authorship has its own fidelity path (``apply_authorship``); the built-in Author/
105
+ # Editor companion columns are neither content nor Person values to remap.
106
+ _PERSON_EXCLUDED = frozenset({"Author", "Editor"})
107
+
108
+ #: Content-approval state: record key (OData escaped form) -> ``ValidateUpdateListItem``
109
+ #: field name. It is ordinary record content, but a *system update* re-approves the
110
+ #: item, so every metadata write that restores timestamps/authorship would silently
111
+ #: discard it; the captured state is therefore folded into that same write
112
+ #: (live-probed: both fields are accepted, and no version is created).
113
+ _APPROVAL_FIELDS = {
114
+ "OData__ModerationStatus": "_ModerationStatus",
115
+ "OData__ModerationComments": "_ModerationComments",
116
+ }
117
+
118
+ #: Approval status of an approved item (0 = draft/pending, 1 = rejected, 2 = approved).
119
+ #: A freshly uploaded document is approved, so only the other states are worth writing.
120
+ _APPROVED_STATUS = "2"
121
+
122
+ #: Moderation columns of a list item. They only exist on a list whose
123
+ #: ``EnableModeration`` is on, so selecting them unconditionally fails outright.
124
+ _MODERATION_FIELDS = ("OData__ModerationStatus", "OData__ModerationComments")
125
+
126
+ #: How many paths a per-run warning names before it summarizes the rest.
127
+ _WARNING_SAMPLE = 5
128
+
129
+ #: Multi-value typed columns. Their ``<name>Id`` companion is a collection of ids
130
+ #: that a ``*`` projection omits (LookupMulti entirely; UserMulti unreliably), so the
131
+ #: source selects them explicitly and the target writes ``{"results": [...]}``.
132
+ _MULTI_VALUE_TYPES = frozenset({"LookupMulti", "UserMulti"})
133
+
134
+ #: Typed columns whose values are remapped (lookup item ids, person logins).
135
+ _TYPED_VALUE_TYPES = frozenset({"Lookup", "LookupMulti", "User", "UserMulti"})
136
+
137
+ #: Properties the source column scans need. Selecting them explicitly keeps the read
138
+ #: independent of whatever ``$select`` a previous caller left on the shared
139
+ #: ``fields`` collection — ``List.fields`` survives a ``capture_list_structure``
140
+ #: read (which selects a different, narrower set), and a field payload that omits
141
+ #: ``AllowMultipleValues`` makes a multi-value column look single-value.
142
+ _SOURCE_FIELD_SELECT = [
143
+ "Id",
144
+ "InternalName",
145
+ "TypeAsString",
146
+ "SchemaXml",
147
+ "Hidden",
148
+ "ReadOnlyField",
149
+ "TextField",
150
+ "AllowMultipleValues",
151
+ ]
152
+
153
+
154
+ #: Choice column types; a multi-choice column stores a collection of strings.
155
+ _CHOICE_TYPES = frozenset({"Choice", "MultiChoice"})
156
+
157
+ #: Column types whose value is a small REST object instead of a scalar.
158
+ _VALUE_OBJECT_TYPES = frozenset({"URL"})
159
+
160
+
161
+ def _allows_multiple_values(field: Any) -> bool:
162
+ """Whether a Lookup/Person column holds many values.
163
+
164
+ ``TypeAsString`` is not authoritative here. A column created from a
165
+ ``Type="Lookup" Mult="TRUE"`` (or ``Type="User" Mult="TRUE"``) schema keeps that
166
+ spelling, so SharePoint reports the *single-value* type and only
167
+ ``AllowMultipleValues`` tells the truth (live-verified). Classifying such a
168
+ column as single-value left its collection of ids unremapped: a multi-lookup
169
+ kept source item ids and a multi-person kept source site-user ids on the target,
170
+ and verification could not see the difference.
171
+ """
172
+ if getattr(field, "type_as_string", None) in _MULTI_VALUE_TYPES:
173
+ return True
174
+ return field.properties.get("AllowMultipleValues") is True
175
+
176
+
177
+ def _is_multi_choice_column(field: Any) -> bool:
178
+ """Whether a Choice column stores a collection of values.
179
+
180
+ ``TypeAsString == "MultiChoice"`` is the only reliable signal. Live-probed: a
181
+ column created from a ``Type="Choice" Mult="TRUE"`` schema reads back as
182
+ ``"Choice"``, stores one value in a single ``nvarchar`` slot (a scalar write
183
+ round-trips, an array is rejected) and does not project ``AllowMultipleValues``
184
+ at all — its schema ``Mult`` flag is misleading, so it is deliberately not used.
185
+ """
186
+ field_type = getattr(field, "type_as_string", None)
187
+ if field_type == "MultiChoice":
188
+ return True
189
+ return field_type in _CHOICE_TYPES and _allows_multiple_values(field)
190
+
191
+
192
+ def _is_value_object_column(field: Any) -> bool:
193
+ """Whether a column holds a REST value object rather than a scalar.
194
+
195
+ A Hyperlink column is the common case: a read returns
196
+ ``{"Url": ..., "Description": ...}``, which a scalar-only record projection
197
+ dropped (a plain string is accepted on write but then makes every subsequent
198
+ *read* of the column fail, live-probed).
199
+ """
200
+ return getattr(field, "type_as_string", None) in _VALUE_OBJECT_TYPES
201
+
202
+
203
+ def _scalar_mapping(value: Any) -> dict | None:
204
+ """A value object as a plain mapping with scalar members, or ``None``.
205
+
206
+ Only a shallow mapping of scalars is accepted, so a navigation property (a
207
+ ``ClientObject``) or a typed payload carrying a nested ``__metadata`` is never
208
+ mistaken for a column value.
209
+ """
210
+ if not isinstance(value, dict) or not value:
211
+ return None
212
+ if any(item is not None and not isinstance(item, (str, int, float, bool)) for item in value.values()):
213
+ return None
214
+ return dict(value)
215
+
216
+
217
+ #: Record columns excluded from the content checksum: server-assigned identity
218
+ #: (``Id``/``GUID``), facets verified separately (timestamps, authorship,
219
+ #: permissions), values the target remaps (``ContentTypeId``), and bookkeeping
220
+ #: (version label, server-derived embed URLs, the navigation ``ParentList``). What
221
+ #: remains is the item's *content* columns, which a faithful copy preserves.
222
+ _CONTENT_EXCLUDED = frozenset(
223
+ {
224
+ "Id",
225
+ "ID",
226
+ "GUID",
227
+ "FileSystemObjectType",
228
+ "Created",
229
+ "Modified",
230
+ "AuthorId",
231
+ "EditorId",
232
+ "HasUniqueRoleAssignments",
233
+ "ContentTypeId",
234
+ "OData__UIVersionString",
235
+ "_UIVersionString",
236
+ "ServerRedirectedEmbedUri",
237
+ "ServerRedirectedEmbedUrl",
238
+ "ParentList",
239
+ "AttachmentFiles",
240
+ }
241
+ )
242
+
243
+ #: Field types whose value is server-derived: a computed column (a link filename, a
244
+ #: doc icon) is a view of the item's identity, not metadata a folder carries.
245
+ _FOLDER_COMPUTED_TYPES = frozenset({"Attachments", "Computed", "File", "WorkflowStatus"})
246
+
247
+
248
+ def _folder_value_columns(fields: list[Any]) -> set[str]:
249
+ """The columns a folder's own metadata can live in (writable, non-system).
250
+
251
+ A read of a folder also returns computed and read-only columns (link filenames,
252
+ compliance flags, version labels); writing those is rejected and comparing them
253
+ would only echo the folder's own name back.
254
+ """
255
+ return {
256
+ field.internal_name
257
+ for field in fields
258
+ if field.internal_name
259
+ # An underscore-prefixed internal name is SharePoint's own storage column; it
260
+ # is not reliably projectable (the same rule the safe fallback projection uses).
261
+ and not field.internal_name.startswith("_")
262
+ and not field.hidden
263
+ and not field.read_only_field
264
+ and field.type_as_string not in _FOLDER_COMPUTED_TYPES
265
+ and field.internal_name not in _FOLDER_RECORD_EXCLUDED
266
+ }
267
+
268
+
269
+ #: Folder (document library) record columns that never travel to the target: the
270
+ #: server-assigned identity and path columns, system metadata (restored by the
271
+ #: fidelity steps), and the folder-specific bookkeeping a read projects. A
272
+ #: ``ContentTypeId`` is kept — a document set's content type is part of what makes
273
+ #: the folder what it is.
274
+ _FOLDER_RECORD_EXCLUDED = (_CONTENT_EXCLUDED - {"ContentTypeId"}) | {
39
275
  "FileRef",
40
276
  "FileDirRef",
41
277
  "FileLeafRef",
42
- "File_x0020_Type",
43
278
  "FSObjType",
44
- "ID",
45
- "GUID",
46
279
  "UniqueId",
47
- "PermMask",
48
- "MetaInfo",
49
- "owshiddenversion",
50
- "AppAuthor",
51
- "AppEditor",
52
- "VirusStatus",
53
- "ScopeId",
54
- "InstanceID",
55
- "Order",
280
+ "SortBehavior",
281
+ "SMTotalFileStreamSize",
282
+ "SMTotalFileCount",
56
283
  }
57
284
 
58
285
 
286
+ def _content_checksum(record: dict, extra_excluded: "frozenset[str]" = frozenset()) -> str:
287
+ """MD5 of an item's content columns in a stable, order-independent form.
288
+
289
+ The list source and target both use this so record content can be reconciled:
290
+ only scalar, multi-value and value-object columns are hashed (navigation
291
+ properties and excluded keys are dropped) and keys are sorted, so the two sides
292
+ agree regardless of property iteration order. A null column is treated as
293
+ absent: the source drops an empty multi-value column while the target reads it
294
+ back as ``None``, and both mean "no value".
295
+ """
296
+ content = {}
297
+ for key, value in record.items():
298
+ if key in _CONTENT_EXCLUDED or key in extra_excluded or value is None:
299
+ continue
300
+ if isinstance(value, (str, int, float, bool, list, tuple)):
301
+ content[key] = value
302
+ continue
303
+ mapping = _scalar_mapping(value)
304
+ if mapping is not None:
305
+ content[key] = mapping
306
+ payload = json.dumps(content, sort_keys=True, default=str)
307
+ return hashlib.md5(payload.encode("utf-8")).hexdigest()
308
+
309
+
310
+ def _folder_record_values(record: dict) -> dict:
311
+ """The column values of a folder item that travel to (or compare with) the target.
312
+
313
+ The projection already narrows the read to the folder's own writable columns; here
314
+ only the identity/system columns are dropped, and an empty value is treated as
315
+ absent on both sides — a source read reports ``""`` where a target read reports
316
+ ``None``, and both mean "no value".
317
+ """
318
+ return {
319
+ key: value for key, value in record.items() if key not in _FOLDER_RECORD_EXCLUDED and value not in (None, "")
320
+ }
321
+
322
+
323
+ def _id_list(value: Any) -> list[Any] | None:
324
+ """Normalize a multi-value ``...Id`` collection into a plain list of ids.
325
+
326
+ A live read returns the collection as a positional mapping (``{0: 1, 1: 2}``);
327
+ a payload this client built may hold ``{"results": [...]}``. Both reduce to the
328
+ same list, which is the form the checksum and the remap work with.
329
+ """
330
+ if isinstance(value, dict):
331
+ if "results" in value:
332
+ value = value["results"]
333
+ else:
334
+ try:
335
+ return [value[i] for i in range(len(value))]
336
+ except (KeyError, TypeError):
337
+ return list(value.values())
338
+ if isinstance(value, (list, tuple)):
339
+ return list(value)
340
+ return None
341
+
342
+
343
+ def _multi_values(value: Any) -> list[Any] | None:
344
+ """A multi-value cell as a plain list of its values, or ``None`` when empty.
345
+
346
+ Accepts every shape a live read or a built payload produces: a positional
347
+ mapping (``{0: "red", 1: "green"}``), a ``{"results": [...]}`` wrapper, a bare
348
+ list, and — because a collection cell may hold exactly one selection — a bare
349
+ scalar.
350
+ """
351
+ if value is None:
352
+ return None
353
+ if isinstance(value, (str, int, float, bool)):
354
+ return [value]
355
+ return _id_list(value)
356
+
357
+
358
+ def _taxonomy_terms(value: Any) -> list[dict[str, str]]:
359
+ """Normalize a taxonomy value to portable ``{"TermGuid": ...}`` terms.
360
+
361
+ A live read shapes a single value as a dict (``{"Label", "TermGuid", "WssId"}``)
362
+ and a multi-value one as a positional mapping (``{0: {...}, 1: {...}}``); a
363
+ payload this client built holds a bare list. All reduce to a list of terms.
364
+ Only ``TermGuid`` is carried: a per-site ``WssId`` is meaningless elsewhere and
365
+ ``Label`` is not authoritative (a read may return the WssId string, and the
366
+ server resolves a write by term id regardless of the label).
367
+ """
368
+ if value is None:
369
+ return []
370
+ if isinstance(value, dict):
371
+ if "TermGuid" in value:
372
+ items: list[Any] = [value]
373
+ elif "results" in value and isinstance(value["results"], (list, tuple)):
374
+ items = list(value["results"])
375
+ else:
376
+ try:
377
+ items = [value[i] for i in range(len(value))]
378
+ except (KeyError, TypeError):
379
+ items = list(value.values())
380
+ elif isinstance(value, (list, tuple)):
381
+ items = list(value)
382
+ else:
383
+ return []
384
+ terms: list[dict[str, str]] = []
385
+ for item in items:
386
+ if isinstance(item, dict):
387
+ guid = item.get("TermGuid")
388
+ else:
389
+ guid = getattr(item, "TermGuid", None)
390
+ if guid:
391
+ terms.append({"TermGuid": str(guid)})
392
+ return terms
393
+
394
+
395
+ def _is_taxonomy_value(value: Any) -> bool:
396
+ """Whether a projected value is a taxonomy term (single dict or multi mapping/list)."""
397
+ return isinstance(value, (dict, list, tuple)) and bool(_taxonomy_terms(value))
398
+
399
+
400
+ def _taxonomy_guids(value: Any) -> list[str]:
401
+ return [term["TermGuid"] for term in _taxonomy_terms(value)]
402
+
403
+
404
+ def _canonicalize_taxonomy_record(record: dict) -> dict:
405
+ """Replace taxonomy values with a sorted list of term ids for comparison.
406
+
407
+ ``Label`` is cosmetic and ``WssId`` is site-local, so neither belongs in the
408
+ content checksum; the term id is the portable identity. Sorting also keeps the
409
+ checksum independent of the order a read happens to return the terms in.
410
+ """
411
+ if not any(_is_taxonomy_value(value) for value in record.values()):
412
+ return record
413
+ canonical = dict(record)
414
+ for key, value in record.items():
415
+ if _is_taxonomy_value(value):
416
+ canonical[key] = sorted(_taxonomy_guids(value))
417
+ return canonical
418
+
419
+
420
+ def _collection_payload(ids: list) -> dict:
421
+ """The JSON shape SharePoint accepts when *creating* a multi-value column.
422
+
423
+ Live-probed: a bare array is rejected on create
424
+ (``InvalidClientQueryException``: "a 'PrimitiveValue' or 'StartObject' node was
425
+ expected") while ``{"results": [...]}`` is accepted. A MERGE *update* is the
426
+ opposite — it accepts the bare array and rejects ``{"results": [...]}`` — so
427
+ only the create path goes through this helper.
428
+ """
429
+ return {"results": ids}
430
+
431
+
432
+ def _sp_utc_timestamp(value: str | None) -> str | None:
433
+ """Normalize a timestamp to the UTC form a *list item* honors.
434
+
435
+ Live-probed: ``ValidateUpdateListItem`` on a plain list item parses an
436
+ ISO-8601 value with a trailing ``Z`` as UTC (and ``datesInUTC=True`` keeps it
437
+ that way), so this form round-trips the exact instant.
438
+ """
439
+ if not value:
440
+ return None
441
+ parsed = parse_datetime(value)
442
+ if parsed is None:
443
+ return value
444
+ if parsed.tzinfo is None:
445
+ parsed = parsed.replace(tzinfo=timezone.utc)
446
+ return parsed.astimezone(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
447
+
448
+
449
+ def _sp_local_timestamp(value: datetime | str | None) -> str | None:
450
+ """Format a *web-local* value as the date form a document item accepts.
451
+
452
+ Live-probed: document-library items ignore ``datesInUTC`` and parse every date
453
+ string in the web's locale, rejecting a trailing ``Z`` (``...must specify a
454
+ valid date within the range of 1/1/1900 and 12/31/8900.``). The space-separated
455
+ ``YYYY-MM-DD HH:MM:SS`` form is accepted and interpreted as local wall-clock,
456
+ so callers must pass the instant already converted to web-local time (see
457
+ ``SharePointLibraryTarget._local_timestamp``).
458
+ """
459
+ if value is None:
460
+ return None
461
+ if isinstance(value, datetime):
462
+ return value.strftime("%Y-%m-%d %H:%M:%S")
463
+ return str(value)
464
+
465
+
466
+ def _report_rejected_fields(result, warnings: list[str], label: str) -> None:
467
+ """Warn about ``ValidateUpdateListItem`` fields the server rejected.
468
+
469
+ A rejected field does not raise over HTTP — the response carries a per-field
470
+ ``HasException``/``ErrorMessage`` — and worse, SharePoint rolls the whole batch
471
+ back, so a sibling ``Created``/``Modified`` write is discarded too. Surfacing it
472
+ keeps that invisible loss honest (and testable).
473
+ """
474
+ values = getattr(result, "value", None) or []
475
+ for value in values:
476
+ if getattr(value, "HasException", False):
477
+ warnings.append(f"{label}: {value.FieldName} rejected ({value.ErrorMessage})")
478
+
479
+
480
+ def _moderation_state(properties: dict) -> dict:
481
+ """The approval fields of a list item, in ``ValidateUpdateListItem`` form.
482
+
483
+ Only present ones are returned: an empty ``_ModerationComments`` normalizes to
484
+ ``None`` server-side, so a blank comment is not carried.
485
+ """
486
+ status = properties.get("OData__ModerationStatus")
487
+ state: dict = {}
488
+ if status is not None:
489
+ state["_ModerationStatus"] = str(status)
490
+ comments = properties.get("OData__ModerationComments")
491
+ if comments:
492
+ state["_ModerationComments"] = str(comments)
493
+ return state
494
+
495
+
496
+ def _version_sort_key(label: str) -> tuple[int, ...]:
497
+ """Sort key for a version label like ``"2.0"`` (numeric parts, non-numeric last)."""
498
+ try:
499
+ return tuple(int(part) for part in str(label).split("."))
500
+ except ValueError:
501
+ return (0,)
502
+
503
+
504
+ #: Library-relative paths SharePoint owns and recreates on the target (its forms
505
+ #: folder and the folder rendering file). Migrating them collides server-side and
506
+ #: clobbers system pages client-side, so the source adapter skips them.
507
+ _LIBRARY_SYSTEM_PATHS = ("Forms", "desktop.ini")
508
+
509
+ #: SiteAssets is the one library that also holds per-site infrastructure — the
510
+ #: site icon and the auto-provisioned OneNote folder.
511
+ _SITE_ASSETS_URL_SUFFIX = "/SiteAssets"
512
+
513
+
514
+ def _site_assets_scaffolding(folder) -> tuple[str, ...]:
515
+ """SiteAssets-only SharePoint-owned entries for this web (empty otherwise).
516
+
517
+ Every modern site provisions ``SiteAssets/<web title> Notebook``; migrating
518
+ it (or reporting it) yields a phantom missing/extra pair because the target's
519
+ folder carries the *target* web's name. The site icon is site branding whose
520
+ bytes are meaningless on another site. Both are skipped on each side.
521
+ """
522
+ url = (folder.server_relative_url or "").rstrip("/")
523
+ if not url.endswith(_SITE_ASSETS_URL_SUFFIX):
524
+ return ()
525
+ web = folder.context.web
526
+ if not web.properties.get("Title"):
527
+ web.ensure_properties(["Title"]).execute_query()
528
+ title = web.title
529
+ names = ["__siteIcon__.png"]
530
+ if title:
531
+ names.append(f"{title} Notebook")
532
+ return tuple(names)
533
+
534
+
535
+ def _is_system_path(rel: str, extra: tuple[str, ...] = ()) -> bool:
536
+ """Whether a library-relative path is SharePoint-owned scaffolding, not user content."""
537
+ entries = (*_LIBRARY_SYSTEM_PATHS, *extra)
538
+ return any(rel == entry or rel.startswith(entry + "/") for entry in entries)
539
+
540
+
59
541
  def is_taxonomy_validation(exc: Exception) -> bool:
60
542
  """True when a request failed because a Managed Metadata (taxonomy) column
61
543
  references a term set / term that no longer exists.
@@ -81,13 +563,367 @@ def taxonomy_internal_names(fields) -> list[str]:
81
563
  return list(dict.fromkeys(names))
82
564
 
83
565
 
566
+ def _perm_mask(role_definition: Any) -> str | None:
567
+ """The decimal ``PermMask`` of a role definition (``BasePermissions`` High/Low)."""
568
+ base = getattr(role_definition, "base_permissions", None)
569
+ if base is None:
570
+ return None
571
+ try:
572
+ return str((int(base.High) << 32) | int(base.Low))
573
+ except (TypeError, ValueError):
574
+ return None
575
+
576
+
577
+ def _is_user_principal(member: Any) -> bool:
578
+ """Whether a role-assignment member is a user (not a group)."""
579
+ ptype = getattr(member, "principal_type", None)
580
+ if ptype is None:
581
+ return False
582
+ if ptype == PrincipalType.User:
583
+ return True
584
+ # ``PrincipalType`` is a plain ``Enum`` (not ``IntEnum``); accept a raw int too.
585
+ return getattr(ptype, "value", ptype) == PrincipalType.User.value
586
+
587
+
588
+ def _is_system_principal(user: Any) -> bool:
589
+ """Whether a resolved user is a tenant system/app account.
590
+
591
+ The Migration API cannot set ``Author``/``Editor`` to a system account, and a
592
+ ``ValidateUpdateListItem`` batch containing one is rejected wholesale — which
593
+ would silently discard the ``Created``/``Modified`` restoration we send in the
594
+ same call. Items created by the migration app itself are authored by such an
595
+ account, so setting it is a no-op anyway; skipping it keeps the timestamp write
596
+ intact.
597
+ """
598
+ login = (getattr(user, "login_name", None) or "").lower()
599
+ return "app@sharepoint" in login or "sharepoint\\system" in login
600
+
601
+
602
+ def _has_unique_role_assignments(securable, *, refresh: bool = False) -> bool:
603
+ """Whether a securable has unique (broken-inheritance) role assignments.
604
+
605
+ SharePoint REST returns *inherited* role assignments too, so reading them
606
+ verbatim would break inheritance on every item and replicate the parent ACL.
607
+ Only items with unique assignments are read/applied (and compared by the
608
+ verifier); inherited items stay inherited on the target.
609
+
610
+ A plain entity read does not return the flag, so an object loaded *before* its
611
+ ACL changed keeps a stale value. The target side passes ``refresh=True``: this
612
+ value decides whether an ACL is applied or compared at all, so a stale
613
+ ``False`` would break inheritance on an item that is already unique (wiping the
614
+ assignments it was supposed to keep) and a stale ``False`` read back after a
615
+ write would report a permission mismatch for an ACL that did land.
616
+ """
617
+ unique = getattr(securable, "has_unique_role_assignments", None)
618
+ if unique is not None and not refresh:
619
+ return bool(unique)
620
+ options = getattr(securable, "query_options", None)
621
+ previous = list(getattr(options, "select", None) or [])
622
+ try:
623
+ securable.select(["HasUniqueRoleAssignments"]).get().execute_query()
624
+ except Exception: # noqa: BLE001 — an unreadable flag is treated as "not unique"
625
+ return False
626
+ finally:
627
+ if options is not None:
628
+ # The projection lives on the object's query options: leaving it on
629
+ # would narrow every later read of the same item.
630
+ options.select = previous
631
+ return bool(securable.properties.get("HasUniqueRoleAssignments"))
632
+
633
+
634
+ def _replay_role_assignments(
635
+ securable,
636
+ principals: "_TargetPrincipals",
637
+ permissions: list[PermissionEntry],
638
+ warnings: list[str],
639
+ label: str,
640
+ ) -> None:
641
+ """Replay an item's unique ACLs onto a target item: additive, never destructive.
642
+
643
+ Every principal is resolved on the target first (users via ``EnsureUser``,
644
+ groups by name, default groups by role kind). Inheritance is broken only when
645
+ the target item still inherits *and* at least one assignment resolved: an item
646
+ whose every principal is unresolvable (a cross-tenant account, an app
647
+ principal) would otherwise end up with an **empty** ACL — inheritance broken,
648
+ nobody granted — which is worse than leaving it inheriting, so that case is
649
+ reported and the item is left alone.
650
+
651
+ A re-run therefore adds only what is missing and never removes an assignment
652
+ the source does not grant. The caller executes the queued requests.
653
+ """
654
+ resolved: list[tuple[Any, Any]] = []
655
+ for entry in permissions:
656
+ principal = principals.principal(entry.principal_name)
657
+ if principal is None:
658
+ continue
659
+ for role_name in entry.roles:
660
+ role = principals.role(role_name)
661
+ if role is None:
662
+ warnings.append(f"permissions {label}: could not resolve role {role_name!r}")
663
+ continue
664
+ resolved.append((principal, role))
665
+ if not resolved:
666
+ warnings.append(
667
+ f"permissions for {label!r} were not restored: no assignment could be resolved on the "
668
+ "target, and breaking inheritance would leave the item with an empty ACL — it still inherits"
669
+ )
670
+ return
671
+ if not _has_unique_role_assignments(securable, refresh=True):
672
+ securable.break_role_inheritance(copy_role_assignments=False, clear_sub_scopes=False)
673
+ for principal, role in resolved:
674
+ securable.add_role_assignment(principal, role)
675
+
676
+
677
+ def _user_login(web, user_id: Any, cache: dict[int, str | None]) -> str | None:
678
+ """Resolve a target user id to its login name, cached."""
679
+ key = parse_int(user_id)
680
+ if key is None:
681
+ return None
682
+ if key in cache:
683
+ return cache[key]
684
+ login: str | None = None
685
+ try:
686
+ user = web.site_users.get_by_id(key).get().execute_query()
687
+ login = user.login_name or None
688
+ except Exception: # noqa: BLE001 — an unresolvable id yields no login
689
+ login = None
690
+ cache[key] = login
691
+ return login
692
+
693
+
694
+ class _MultiValueCreateTarget:
695
+ """An upsert target that reshapes multi-value columns only when creating.
696
+
697
+ A multi-value Lookup/Person column is created with the ``{"results": [...]}``
698
+ wire shape but updated with a bare array (live-probed), so ``keyed_queue`` needs
699
+ to reshape the creates and leave the updates alone. Everything else delegates.
700
+ """
701
+
702
+ def __init__(self, target: Any, reshape: Callable[[dict], dict]) -> None:
703
+ self._target = target
704
+ self._reshape = reshape
705
+
706
+ @property
707
+ def key_field(self) -> str:
708
+ return self._target.key_field
709
+
710
+ def ensure_key_field(self) -> None:
711
+ self._target.ensure_key_field()
712
+
713
+ def load_keys(self) -> Any:
714
+ return self._target.load_keys()
715
+
716
+ def create_records(self, records: list[dict]) -> None:
717
+ self._target.create_records([self._reshape(record) for record in records])
718
+
719
+ def update_record(self, item_id: Any, record: dict) -> None:
720
+ self._target.update_record(item_id, record)
721
+
722
+
723
+ class _DefaultGroups:
724
+ """Maps a web's associated default groups (Owners/Members/Visitors).
725
+
726
+ Default groups are titled after the site (``team Owners``), so a source and
727
+ target in the same tenant rarely share the exact name. These groups are used
728
+ both to resolve a source name onto the target *and* to normalize the name to a
729
+ canonical ``default:<Kind>`` token so the permission diff compares like with
730
+ like (a renamed site still verifies as preserved). Loaded once, lazily.
731
+ """
732
+
733
+ ATTRS = (
734
+ ("Owners", "associated_owner_group"),
735
+ ("Members", "associated_member_group"),
736
+ ("Visitors", "associated_visitor_group"),
737
+ )
738
+
739
+ def __init__(self, web) -> None:
740
+ self._web = web
741
+ self._by_kind: dict[str, Any] | None = None
742
+ self._by_title: dict[str, str] = {}
743
+
744
+ def _load(self) -> None:
745
+ if self._by_kind is not None:
746
+ return
747
+ self._by_kind = {}
748
+ for kind, attr in self.ATTRS:
749
+ group = getattr(self._web, attr, None)
750
+ if group is None:
751
+ continue
752
+ try:
753
+ group.get().execute_query()
754
+ except Exception: # noqa: BLE001 — an unreadable group is skipped
755
+ continue
756
+ self._by_kind[kind] = group
757
+ title = getattr(group, "title", None) or getattr(group, "login_name", None)
758
+ if title:
759
+ self._by_title[title] = kind
760
+
761
+ def group(self, kind: str):
762
+ self._load()
763
+ return self._by_kind.get(kind) if self._by_kind else None
764
+
765
+ def normalize(self, name: str) -> str:
766
+ self._load()
767
+ kind = self._by_title.get(name)
768
+ return f"default:{kind}" if kind else name
769
+
770
+
771
+ class _TargetPrincipals:
772
+ """Resolve source principals and role definitions on a target web (cached).
773
+
774
+ Users are ensured on the site (``EnsureUser``) so their numeric id can be used
775
+ for authorship and role assignments; groups are matched by name, and the
776
+ default SharePoint groups (Owners/Members/Visitors) fall back to the target
777
+ web's associated groups so a renamed site (``team`` -> ``team_out``) still
778
+ maps its role assignments. Anything that cannot be resolved is skipped with a
779
+ warning (same-tenant, best-effort).
780
+ """
781
+
782
+ def __init__(self, web, warnings: list[str]) -> None:
783
+ self._web = web
784
+ self._warnings = warnings
785
+ self._users: dict[str, Any] = {}
786
+ self._roles: "dict[str, RoleDefinition] | None" = None
787
+ self._defaults = _DefaultGroups(web)
788
+
789
+ @staticmethod
790
+ def _strip_claims(name: str) -> str:
791
+ return name.rsplit("|", 1)[-1] if name.startswith("i:0#") else name
792
+
793
+ def normalize(self, name: str) -> str:
794
+ """Canonical principal name (default groups collapse to ``default:<Kind>``)."""
795
+ return self._defaults.normalize(name)
796
+
797
+ def user(self, login: str | None):
798
+ """Ensure a user login on the target site and return its ``User`` object."""
799
+ if not login:
800
+ return None
801
+ login = self._strip_claims(login)
802
+ if login in self._users:
803
+ return self._users[login]
804
+ obj = None
805
+ try:
806
+ obj = self._web.ensure_user(login).execute_query()
807
+ except Exception as e: # noqa: BLE001 — an unresolvable principal is skipped
808
+ self._warnings.append(f"could not ensure target user {login!r}: {e}")
809
+ self._users[login] = obj
810
+ return obj
811
+
812
+ def principal(self, name: str):
813
+ """Resolve a source principal (user or group) to a target principal object."""
814
+ if not name:
815
+ return None
816
+ login = self._strip_claims(name)
817
+ if login.startswith("default:"):
818
+ return self._defaults.group(login.split(":", 1)[1])
819
+ if "@" in login:
820
+ return self.user(login)
821
+ group = None
822
+ try:
823
+ group = self._web.site_groups.get_by_name(login).get().execute_query()
824
+ except Exception: # noqa: BLE001 — fall back to the default groups below
825
+ group = None
826
+ if group is None:
827
+ kind = login.rsplit(" ", 1)[-1]
828
+ if kind in {"Owners", "Members", "Visitors"}:
829
+ group = self._defaults.group(kind)
830
+ if group is not None:
831
+ return group
832
+ self._warnings.append(f"could not resolve principal {name!r} on the target")
833
+ return None
834
+
835
+ def role(self, name: str) -> "RoleDefinition | None":
836
+ """Resolve (and cache) a target role definition by name."""
837
+ if self._roles is None:
838
+ loaded = self._web.role_definitions.get().execute_query()
839
+ self._roles = {rd.name: rd for rd in loaded if rd.name}
840
+ return self._roles.get(name)
841
+
842
+
843
+ def _read_role_assignments(
844
+ securable,
845
+ resolve: Callable[[Any], "Principal | None"] | None = None,
846
+ normalize: Callable[[str], str] | None = None,
847
+ ) -> list[PermissionEntry]:
848
+ """Read a securable object's role assignments into ``PermissionEntry``s.
849
+
850
+ One entry per principal (user or group), keyed by login name; the target uses
851
+ the same shape so the permission diff compares like with like. ``normalize``
852
+ (when supplied) canonicalizes a principal name — default groups collapse to
853
+ ``default:<Kind>`` so a renamed site still compares as preserved. Role names are
854
+ paired with their decimal ``PermMask`` (``role_masks``), and — when ``resolve``
855
+ is supplied — a user principal is enriched with its PUID/display name/email so
856
+ the server-side package target can emit a faithful ``UserGroup.xml`` entry.
857
+ """
858
+ assignments = securable.role_assignments.expand(["Member", "RoleDefinitionBindings"]).get().execute_query()
859
+ result: list[PermissionEntry] = []
860
+ for assignment in assignments:
861
+ member = assignment.member
862
+ name = member.login_name or member.user_principal_name
863
+ if not name:
864
+ continue
865
+ roles: list[str] = []
866
+ role_masks: dict[str, str] = {}
867
+ for role in assignment.role_definition_bindings:
868
+ if not role.name:
869
+ continue
870
+ roles.append(role.name)
871
+ mask = _perm_mask(role)
872
+ if mask is not None:
873
+ role_masks[role.name] = mask
874
+ entry = PermissionEntry(
875
+ principal_name=normalize(name) if normalize is not None else name,
876
+ roles=roles,
877
+ role_masks=role_masks,
878
+ )
879
+ if resolve is not None and _is_user_principal(member):
880
+ principal = resolve(getattr(member, "id", None))
881
+ if principal is not None:
882
+ entry.system_id = principal.system_id
883
+ entry.display_name = principal.display_name
884
+ entry.email = principal.email
885
+ result.append(entry)
886
+ return result
887
+
888
+
84
889
  class SharePointListSource:
85
890
  """Enumerates a SharePoint list's items into record migration items."""
86
891
 
892
+ # Marks this source as emitting list-item attachments as extra items (see DataSource).
893
+ supports_attachments = True
894
+
895
+ # Marks this source as annotating Person columns with a portable login name so the
896
+ # target can resolve them (see ``_annotate_person_logins``).
897
+ supports_typed_values = True
898
+
899
+ def rebind(self) -> "SharePointListSource":
900
+ """This source on its own cloned context, so another thread can drive it.
901
+
902
+ A context owns one pending-query queue: two adapters sharing it interleave
903
+ their deferred queries. Re-addressing the same list (by id) on a ``clone``
904
+ — which shares the authenticated transport — lets a session run several
905
+ list jobs in parallel over one connection pool. Read caches are per-run and
906
+ deliberately not carried over.
907
+ """
908
+ return SharePointListSource(_cloned_list(self._list), self._select)
909
+
87
910
  def __init__(self, source_list: "SPList", select: list[str] | None = None) -> None:
88
911
  self._list = source_list
89
912
  self._select = select
90
913
  self._records: dict[str, dict] = {}
914
+ self._items: dict[str, Any] = {}
915
+ self._attachments: dict[str, Any] = {}
916
+ self._users: dict[int, Principal | None] = {}
917
+ self._default_groups: _DefaultGroups | None = None
918
+ self._source_fields_cache: list[Any] | None = None
919
+ self._user_columns_cache: set[str] | None = None
920
+ self._multi_columns_cache: dict[str, str] | None = None
921
+ self._skipped_columns_cache: set[str] | None = None
922
+ self._taxonomy_columns_cache: dict[str, bool] | None = None
923
+ self._taxonomy_note_columns_cache: set[str] | None = None
924
+ self._multi_choice_columns_cache: set[str] | None = None
925
+ self._value_object_columns_cache: set[str] | None = None
926
+ self._folder_records_cache: dict[str, dict] | None = None
91
927
  self.warnings: list[str] = []
92
928
 
93
929
  def label(self) -> str:
@@ -115,11 +951,29 @@ class SharePointListSource:
115
951
  loaded = self._load_items(["Id", "Title"])
116
952
  return self._project(loaded, progress)
117
953
 
118
- def _load_items(self, select: list[str] | None):
954
+ def _load_items(self, select: list[str] | None, folder_only: bool = False):
119
955
  items = self._list.items
120
- if select:
121
- items = items.select(select)
122
- return items.get_all().execute_query()
956
+ # A full read projects ``*`` plus the system metadata so author/editor ids
957
+ # and the unique-ACL flag are captured in one query (``*`` omits them);
958
+ # an explicit/safe projection is honored as-is.
959
+ if select is None:
960
+ columns = ["*", *_METADATA_SELECT]
961
+ # A ``*`` projection also omits multi-value Lookup ids (and returns
962
+ # multi-person ids only inconsistently); select each ``<name>Id``
963
+ # explicitly so the values are not silently lost.
964
+ for name in self._multi_columns():
965
+ key = f"{name}Id"
966
+ if key not in columns:
967
+ columns.append(key)
968
+ # Expand attachments so they can be migrated alongside their item.
969
+ query = items.select(columns).expand(["AttachmentFiles"])
970
+ if folder_only:
971
+ query = query.filter("FSObjType eq 1")
972
+ return query.get_all().execute_query()
973
+ query = items.select(select)
974
+ if folder_only:
975
+ query = query.filter("FSObjType eq 1")
976
+ return query.get_all().execute_query()
123
977
 
124
978
  def _safe_select(self) -> list[str]:
125
979
  """Fallback projection: visible, non-system columns minus Managed Metadata.
@@ -138,63 +992,1408 @@ class SharePointListSource:
138
992
  continue
139
993
  if internal_name.startswith("_") or getattr(field, "hidden", False):
140
994
  continue # hidden/system metadata — not safe to project
141
- if internal_name in _SYSTEM_INTERNAL_NAMES:
995
+ if internal_name in SYSTEM_FIELD_NAMES:
142
996
  continue
143
997
  columns.append(internal_name)
144
998
  return columns
145
999
 
146
1000
  def _project(self, loaded, progress: MigrationProgress) -> list[MigrationItem]:
1001
+ records = self._project_records(loaded)
147
1002
  result: list[MigrationItem] = []
148
- for item in loaded:
149
- record = {k: v for k, v in item.properties.items() if not str(k).startswith("__")}
150
- self._records[str(item.id)] = record
1003
+ pending_attachments: list[tuple[str, Any]] = []
1004
+ for item, record in zip(loaded, records):
1005
+ item_id = str(item.id)
1006
+ self._records[item_id] = record
1007
+ self._items[item_id] = item
1008
+ author_id = parse_int(record.get("AuthorId"))
1009
+ editor_id = parse_int(record.get("EditorId"))
1010
+ planned = MigrationItem(
1011
+ source_path=f"{self._list.title}/{item_id}",
1012
+ dest_path=item_id,
1013
+ item_type="record",
1014
+ modified=iso_or_none(record.get("Modified")),
1015
+ created=iso_or_none(record.get("Created")),
1016
+ author_id=author_id,
1017
+ editor_id=editor_id,
1018
+ )
1019
+ # Resolve the source author/editor once so an authorship-preserving
1020
+ # target can restore them by login name (ids are tenant-local).
1021
+ if author_id is not None:
1022
+ planned.author = self._principal_for(author_id)
1023
+ if editor_id is not None:
1024
+ planned.editor = self._principal_for(editor_id)
1025
+ result.append(planned)
1026
+ for attachment in item.properties.get("AttachmentFiles") or []:
1027
+ pending_attachments.append((item_id, attachment))
1028
+ emit_progress(progress, done=len(result), stage="planning", items=[item])
1029
+ # Attachments come after every record so the target can create all parent
1030
+ # items before it resolves and uploads their attachments.
1031
+ for item_id, attachment in pending_attachments:
1032
+ name = getattr(attachment, "file_name", None)
1033
+ if not name:
1034
+ self.warnings.append(f"skipped an attachment without a file name on item {item_id}")
1035
+ continue
1036
+ dest_path = f"{item_id}/{name}"
1037
+ self._attachments[dest_path] = attachment
151
1038
  result.append(
152
1039
  MigrationItem(
153
- source_path=f"{self._list.title}/{item.id}",
154
- dest_path=str(item.id),
155
- item_type="record",
1040
+ source_path=f"{self._list.title}/{dest_path}",
1041
+ dest_path=dest_path,
1042
+ item_type="attachment",
156
1043
  )
157
1044
  )
158
- emit_progress(progress, done=len(result), stage="planning", items=[item])
1045
+ emit_progress(progress, done=len(result), stage="planning", items=[attachment])
159
1046
  return result
160
1047
 
161
- def read(self, item: MigrationItem) -> dict:
1048
+ def _project_records(self, loaded, report_skipped: bool = True) -> list[dict]:
1049
+ # Project every loaded property — not the collection's literal ``select``.
1050
+ # Passing ``["*", ...]`` straight through emitted ``{"*": None, ...}``, so
1051
+ # migrated records carried no field values at all. ``AttachmentFiles`` is a
1052
+ # navigation property (objects, not a scalar column) and is excluded; the
1053
+ # target writes attachments separately.
1054
+ select = sorted(
1055
+ {key for item in loaded for key in item.properties if key != "AttachmentFiles"} - _NON_WRITABLE_SELECT
1056
+ )
1057
+ records = records_from_items(list(loaded), select, set(), raw=True)
1058
+ # A REST item create accepts scalar column values only. A full read also
1059
+ # returns navigation properties (``ParentList``) and typed values
1060
+ # (lookups/persons, e.g. ``PredecessorsId`` / ``AssignedTo``) whose JSON
1061
+ # objects carry no ``__metadata.type`` here, so the create batch is
1062
+ # rejected with ``InvalidClientQueryException``. Typed-value remapping is
1063
+ # not supported yet, so drop them and say so rather than fail the run.
1064
+ dropped: set[str] = set()
1065
+ multi = self._multi_columns()
1066
+ multi_keys = {f"{name}Id" for name in multi} | {f"{name}StringId" for name in multi}
1067
+ choices = self._multi_choice_columns()
1068
+ taxonomy = self._taxonomy_columns()
1069
+ value_objects = self._value_object_columns()
1070
+ for record in records:
1071
+ for key, value in list(record.items()):
1072
+ if key in multi_keys:
1073
+ continue # handled by ``_normalize_multi_values``
1074
+ if key in choices:
1075
+ continue # handled by ``_normalize_multi_choice_values``
1076
+ if key in taxonomy:
1077
+ continue # handled by ``_project_taxonomy_values``
1078
+ if key in value_objects and _scalar_mapping(value) is not None:
1079
+ record[key] = _scalar_mapping(value)
1080
+ continue # a value object (``{"Url", "Description"}``) is writable as-is
1081
+ if value is not None and not isinstance(value, (str, int, float, bool)):
1082
+ record.pop(key)
1083
+ if key not in _NAVIGATION_SELECT:
1084
+ dropped.add(key)
1085
+ if dropped:
1086
+ self.warnings.append(
1087
+ f"skipped non-scalar column(s) with no typed-value mapping: {', '.join(sorted(dropped))}"
1088
+ )
1089
+ # Structure provisioning skips hidden columns, so their typed values (and
1090
+ # the text companion) have nowhere to land on the target; drop both rather
1091
+ # than fail the create on an unknown column.
1092
+ skipped = self._skipped_columns()
1093
+ if skipped:
1094
+ skipped_keys = {f"{name}Id" for name in skipped} | {f"{name}StringId" for name in skipped}
1095
+ for record in records:
1096
+ for key in skipped_keys:
1097
+ record.pop(key, None)
1098
+ if report_skipped:
1099
+ self.warnings.append(
1100
+ f"skipped hidden typed column(s) not replicated by structure provisioning: "
1101
+ f"{', '.join(sorted(skipped))}"
1102
+ )
1103
+ self._project_taxonomy_values(records)
1104
+ self._normalize_multi_values(records)
1105
+ self._normalize_multi_choice_values(records)
1106
+ self._annotate_person_logins(records)
1107
+ return records
1108
+
1109
+ def folder_records(self) -> dict[str, dict]:
1110
+ """Column values of this list's folders, keyed by their server-relative URL.
1111
+
1112
+ A document library's folders are list items too: a document set or a managed
1113
+ folder carries its own column values, so a target that only created the empty
1114
+ folder would silently lose them. The values go through the same projection as
1115
+ an item's (typed values normalized, system and navigation columns dropped), so
1116
+ the target can write them onto the folder's underlying item. The read is
1117
+ narrowed to the folder's writable columns (see :meth:`folder_projection`): a
1118
+ ``*`` read also returns system and computed columns (compliance flags, link
1119
+ filenames, version labels) that an update would reject and that carry no
1120
+ portable value.
1121
+ """
1122
+ if self._folder_records_cache is None:
1123
+ records: dict[str, dict] = {}
1124
+ try:
1125
+ loaded = self._load_items(self.folder_projection(), folder_only=True)
1126
+ except Exception as e: # noqa: BLE001 — folder values are best-effort
1127
+ self.warnings.append(f"folder column values could not be read: {e}")
1128
+ loaded = []
1129
+ # The folder projection already excluded the columns an item record would
1130
+ # report as unmigratable, so those messages would describe nothing.
1131
+ for record in self._project_records(loaded, report_skipped=False) if loaded else []:
1132
+ url = record.get("FileRef")
1133
+ if not isinstance(url, str) or not url:
1134
+ continue
1135
+ values = _folder_record_values(record)
1136
+ if values:
1137
+ records[url.rstrip("/")] = values
1138
+ self._folder_records_cache = records
1139
+ return self._folder_records_cache
1140
+
1141
+ def folder_projection(self) -> list[str]:
1142
+ """The columns that carry a folder's own metadata, plus what typed values need.
1143
+
1144
+ A folder has no separate create payload: its values are read back as a record,
1145
+ written onto the folder's item and compared the same way — so the projection
1146
+ must include the companions the typed-value normalization reads (``<name>Id``
1147
+ for Lookup/Person values, the hidden note of a Managed Metadata column).
1148
+ """
1149
+ writable = _folder_value_columns(self._source_fields())
1150
+ # ``FileRef`` keys the record (it is the folder's identity, not a value).
1151
+ columns = ["ContentTypeId", "FileRef", *sorted(writable)]
1152
+ # Lookup and Person values are carried as item ids / logins under
1153
+ # ``<name>Id``; the column itself is carried in the record too.
1154
+ single_lookups = {
1155
+ field.internal_name
1156
+ for field in self._source_fields()
1157
+ if field.internal_name and field.type_as_string == "Lookup" and not _allows_multiple_values(field)
1158
+ }
1159
+ for name in sorted((single_lookups | self._user_columns() | set(self._multi_columns())) & writable):
1160
+ key = f"{name}Id"
1161
+ if key not in columns:
1162
+ columns.append(key)
1163
+ for note in self._taxonomy_note_columns():
1164
+ if note not in columns:
1165
+ columns.append(note)
1166
+ return columns
1167
+
1168
+ def _source_fields(self) -> list[Any]:
1169
+ """The source list's field definitions, read once and shared by every scan."""
1170
+ if self._source_fields_cache is None:
1171
+ self._source_fields_cache = list(self._list.fields.select(list(_SOURCE_FIELD_SELECT)).get().execute_query())
1172
+ return self._source_fields_cache
1173
+
1174
+ def _taxonomy_columns(self) -> dict[str, bool]:
1175
+ """The source's Managed Metadata columns (internal name -> allows many)."""
1176
+ if self._taxonomy_columns_cache is None:
1177
+ columns: dict[str, bool] = {}
1178
+ notes: set[str] = set()
1179
+ try:
1180
+ fields = self._source_fields()
1181
+ by_id = {
1182
+ normalize_guid(getattr(field, "id", None)): getattr(field, "internal_name", None) for field in fields
1183
+ }
1184
+ for field in fields:
1185
+ internal_name = getattr(field, "internal_name", None)
1186
+ if not internal_name:
1187
+ continue
1188
+ field_type = getattr(field, "type_as_string", None)
1189
+ schema = getattr(field, "schema_xml", None) or ""
1190
+ if field_type not in _TAXONOMY_FIELD_TYPES and "TermSetId" not in schema:
1191
+ continue
1192
+ columns[internal_name] = field_type == "TaxonomyFieldTypeMulti" or 'Mult="TRUE"' in schema
1193
+ note = by_id.get(normalize_guid(field.properties.get("TextField")))
1194
+ if note:
1195
+ notes.add(note)
1196
+ except Exception as e: # noqa: BLE001 — values stay un-remapped, never fatal
1197
+ self.warnings.append(f"could not read source columns for taxonomy remapping: {e}")
1198
+ self._taxonomy_columns_cache = columns
1199
+ self._taxonomy_note_columns_cache = notes
1200
+ return self._taxonomy_columns_cache
1201
+
1202
+ def _taxonomy_note_columns(self) -> set[str]:
1203
+ """The hidden note companions of the source's taxonomy columns."""
1204
+ self._taxonomy_columns()
1205
+ return self._taxonomy_note_columns_cache or set()
1206
+
1207
+ def _project_taxonomy_values(self, records: list[dict]) -> None:
1208
+ """Project taxonomy columns as bare ``[{"TermGuid": ...}]`` term lists.
1209
+
1210
+ The target recreates the column against the same term set and rebuilds the
1211
+ write payload, so only the portable term id travels. The hidden note
1212
+ companion (if a projection happens to include it) is dropped.
1213
+ """
1214
+ columns = self._taxonomy_columns()
1215
+ if not columns:
1216
+ return
1217
+ notes = self._taxonomy_note_columns()
1218
+ for record in records:
1219
+ for note in notes:
1220
+ record.pop(note, None)
1221
+ for name in columns:
1222
+ terms = _taxonomy_terms(record.get(name))
1223
+ if terms:
1224
+ record[name] = terms
1225
+ else:
1226
+ record.pop(name, None)
1227
+
1228
+ def _typed_columns(self) -> tuple[set[str], dict[str, str], set[str]]:
1229
+ """The source's Person and multi-value columns, read once.
1230
+
1231
+ Returns ``(single-value User columns, {multi-value column: field type},
1232
+ hidden typed columns)``. The field type tells a multi-lookup (remapped by
1233
+ item id) from a multi-person (remapped by login). Hidden typed columns are
1234
+ reported separately because structure provisioning does not replicate them.
1235
+ """
1236
+ if self._user_columns_cache is None or self._multi_columns_cache is None or self._skipped_columns_cache is None:
1237
+ users: set[str] = set()
1238
+ multi: dict[str, str] = {}
1239
+ skipped: set[str] = set()
1240
+ try:
1241
+ for field in self._source_fields():
1242
+ internal_name = getattr(field, "internal_name", None)
1243
+ if not internal_name or internal_name in _PERSON_EXCLUDED:
1244
+ continue
1245
+ field_type = getattr(field, "type_as_string", None)
1246
+ if field_type not in _TYPED_VALUE_TYPES:
1247
+ continue
1248
+ # Structure replay skips hidden columns, so the target never
1249
+ # gets them; projecting their values would fail the write.
1250
+ if getattr(field, "hidden", None) is True:
1251
+ skipped.add(internal_name)
1252
+ elif field_type.startswith("User"):
1253
+ if _allows_multiple_values(field):
1254
+ multi[internal_name] = "UserMulti"
1255
+ else:
1256
+ users.add(internal_name)
1257
+ elif _allows_multiple_values(field):
1258
+ multi[internal_name] = "LookupMulti"
1259
+ except Exception as e: # noqa: BLE001 — without field types ids stay raw
1260
+ self.warnings.append(f"could not read source columns for typed-value remapping: {e}")
1261
+ self._user_columns_cache = users
1262
+ self._multi_columns_cache = multi
1263
+ self._skipped_columns_cache = skipped
1264
+ return self._user_columns_cache, self._multi_columns_cache, self._skipped_columns_cache
1265
+
1266
+ def _user_columns(self) -> set[str]:
1267
+ """The source's single-value Person columns (internal names)."""
1268
+ return self._typed_columns()[0]
1269
+
1270
+ def _multi_columns(self) -> dict[str, str]:
1271
+ """The source's multi-value Lookup/Person columns (internal name -> field type)."""
1272
+ return self._typed_columns()[1]
1273
+
1274
+ def _skipped_columns(self) -> set[str]:
1275
+ """The source's hidden Person/multi-value columns (not replicated on the target)."""
1276
+ return self._typed_columns()[2]
1277
+
1278
+ def _multi_choice_columns(self) -> set[str]:
1279
+ """The source's multi-choice columns (internal names)."""
1280
+ if self._multi_choice_columns_cache is None:
1281
+ names: set[str] = set()
1282
+ try:
1283
+ names = {
1284
+ field.internal_name
1285
+ for field in self._source_fields()
1286
+ if getattr(field, "internal_name", None) and _is_multi_choice_column(field)
1287
+ }
1288
+ except Exception as e: # noqa: BLE001 — values stay un-normalized, never fatal
1289
+ self.warnings.append(f"could not read source columns for multi-choice values: {e}")
1290
+ self._multi_choice_columns_cache = names
1291
+ return self._multi_choice_columns_cache
1292
+
1293
+ def _value_object_columns(self) -> set[str]:
1294
+ """The source's columns that hold a REST value object (e.g. a hyperlink)."""
1295
+ if self._value_object_columns_cache is None:
1296
+ names: set[str] = set()
1297
+ try:
1298
+ names = {
1299
+ field.internal_name
1300
+ for field in self._source_fields()
1301
+ if getattr(field, "internal_name", None) and _is_value_object_column(field)
1302
+ }
1303
+ except Exception as e: # noqa: BLE001 — values are dropped, never fatal
1304
+ self.warnings.append(f"could not read source columns for value-object values: {e}")
1305
+ self._value_object_columns_cache = names
1306
+ return self._value_object_columns_cache
1307
+
1308
+ def _annotate_person_logins(self, records: list[dict]) -> None:
1309
+ """Replace each Person column's site-user id with the user's login name.
1310
+
1311
+ A site-user id is only meaningful inside its own site collection, so it is
1312
+ meaningless on the target. The login *is* portable, and the target resolves
1313
+ it back to (a possibly different) target site-user id with ``EnsureUser``.
1314
+ A person the source cannot resolve is dropped and reported rather than
1315
+ copied as a wrong id.
1316
+ """
1317
+ columns = self._user_columns()
1318
+ if not columns:
1319
+ return
1320
+ for record in records:
1321
+ for name in columns:
1322
+ # ``<name>StringId`` is a read-only text companion holding the user
1323
+ # id; leaving it in the payload makes REST ignore the remapped
1324
+ # ``<name>Id`` and keep the source id.
1325
+ record.pop(f"{name}StringId", None)
1326
+ key = f"{name}Id"
1327
+ user_id = parse_int(record.get(key))
1328
+ if user_id is None:
1329
+ continue
1330
+ principal = self._principal_for(user_id)
1331
+ login = principal.login_name if principal else None
1332
+ if login:
1333
+ record[key] = login
1334
+ else:
1335
+ record.pop(key, None)
1336
+ self.warnings.append(
1337
+ f"person column '{name}' value {user_id} could not be resolved to a login; left empty"
1338
+ )
1339
+
1340
+ def _normalize_multi_values(self, records: list[dict]) -> None:
1341
+ """Project each multi-value column's ids as a plain list the target can remap.
1342
+
1343
+ A multi-person column additionally carries the portable login names instead
1344
+ of the site-local ids, matching the single-value Person handling.
1345
+ """
1346
+ multi = self._multi_columns()
1347
+ if not multi:
1348
+ return
1349
+ for record in records:
1350
+ for name, field_type in multi.items():
1351
+ record.pop(f"{name}StringId", None)
1352
+ key = f"{name}Id"
1353
+ ids = _id_list(record.get(key))
1354
+ parsed: list[int] = []
1355
+ for value in ids or []:
1356
+ user_id = parse_int(value)
1357
+ if user_id is None:
1358
+ parsed = []
1359
+ break
1360
+ parsed.append(user_id)
1361
+ if not parsed:
1362
+ record.pop(key, None)
1363
+ continue
1364
+ if field_type == "UserMulti":
1365
+ logins: list[str] = []
1366
+ for user_id in parsed:
1367
+ principal = self._principal_for(user_id)
1368
+ login = principal.login_name if principal else None
1369
+ if login:
1370
+ logins.append(login)
1371
+ else:
1372
+ self.warnings.append(
1373
+ f"multi-person column '{name}' value {user_id} could not be resolved "
1374
+ "to a login; the value was left out"
1375
+ )
1376
+ if logins:
1377
+ record[key] = logins
1378
+ else:
1379
+ record.pop(key, None)
1380
+ else:
1381
+ record[key] = parsed
1382
+
1383
+ def _normalize_multi_choice_values(self, records: list[dict]) -> None:
1384
+ """Project each multi-choice column as a plain list of its selected values.
1385
+
1386
+ A live read returns the collection as a positional mapping
1387
+ (``{0: "red", 1: "green"}``); the source records it as a bare list, which is
1388
+ what the checksum compares and what the target wraps for a create. An empty
1389
+ selection is dropped so the column reads back empty rather than as an empty
1390
+ collection.
1391
+ """
1392
+ names = self._multi_choice_columns()
1393
+ if not names:
1394
+ return
1395
+ for record in records:
1396
+ for name in names:
1397
+ if name not in record:
1398
+ continue
1399
+ values = _multi_values(record.get(name))
1400
+ if values:
1401
+ record[name] = values
1402
+ else:
1403
+ record.pop(name, None)
1404
+
1405
+ def read(self, item: MigrationItem) -> object:
1406
+ if item.item_type == "attachment":
1407
+ return self._attachment_content(item)
162
1408
  return self._records.get(item.dest_path, {})
163
1409
 
1410
+ def _attachment_content(self, item: MigrationItem) -> bytes:
1411
+ attachment = self._attachments.get(item.dest_path)
1412
+ if attachment is None:
1413
+ raise FileNotFoundError(item.source_path)
1414
+ return cast(bytes, attachment.get_content().execute_query().value)
1415
+
164
1416
  def checksum(self, item: MigrationItem) -> str:
165
- payload = record_to_json(self._records.get(item.dest_path, {}))
166
- return hashlib.md5(payload.encode("utf-8")).hexdigest()
1417
+ if item.item_type == "attachment":
1418
+ return hashlib.md5(self._attachment_content(item)).hexdigest()
1419
+ return _content_checksum(_canonicalize_taxonomy_record(self._records.get(item.dest_path, {})))
1420
+
1421
+ def read_metadata(self, item: MigrationItem) -> dict | None:
1422
+ """Comparable attributes of the source item (for the post-run metadata diff)."""
1423
+ source_item = self._items.get(item.dest_path)
1424
+ if source_item is None:
1425
+ return None
1426
+ properties = source_item.properties
1427
+ return {
1428
+ "created": iso_or_none(properties.get("Created")),
1429
+ "modified": iso_or_none(properties.get("Modified")),
1430
+ }
1431
+
1432
+ def read_authorship(self, item: MigrationItem) -> tuple[str | None, str | None]:
1433
+ """The source author/editor login names (for the authorship diff)."""
1434
+ return (
1435
+ item.author.login_name if item.author else None,
1436
+ item.editor.login_name if item.editor else None,
1437
+ )
1438
+
1439
+ def _normalize_name(self, name: str) -> str:
1440
+ """Canonicalize a principal name (default groups -> ``default:<Kind>``)."""
1441
+ context = getattr(self._list, "context", None)
1442
+ web = getattr(context, "web", None) if context is not None else None
1443
+ if web is None:
1444
+ return name
1445
+ if self._default_groups is None:
1446
+ self._default_groups = _DefaultGroups(web)
1447
+ return self._default_groups.normalize(name)
1448
+
1449
+ def read_permissions(self, item: MigrationItem) -> list[PermissionEntry]:
1450
+ """Read the item's *unique* role assignments (best-effort ACL preservation).
1451
+
1452
+ Inherited items return ``[]`` — REST would otherwise report the parent's
1453
+ ACL, and copying it would break inheritance on every item.
1454
+ """
1455
+ source_item = self._items.get(item.dest_path)
1456
+ if source_item is None or not _has_unique_role_assignments(source_item):
1457
+ return []
1458
+ return _read_role_assignments(source_item, resolve=self._principal_for, normalize=self._normalize_name)
1459
+
1460
+ def _principal_for(self, user_id: Any) -> "Principal | None":
1461
+ """Resolve a site-user id to a :class:`Principal` (login + PUID), cached."""
1462
+ key = parse_int(user_id)
1463
+ if key is None:
1464
+ return None
1465
+ if key in self._users:
1466
+ return self._users[key]
1467
+ principal: "Principal | None" = None
1468
+ try:
1469
+ user = self._list.context.web.site_users.get_by_id(cast("str", key)).get().execute_query()
1470
+ user_id_info = user.properties.get("UserId")
1471
+ system_id = normalize_puid(getattr(user_id_info, "NameId", None))
1472
+ principal = Principal(
1473
+ login_name=user.login_name or "",
1474
+ system_id=system_id,
1475
+ display_name=user.title,
1476
+ email=user.properties.get("Email"),
1477
+ )
1478
+ except Exception as e: # noqa: BLE001 — a missing user degrades to no authorship
1479
+ self.warnings.append(f"user {key} could not be resolved: {e}")
1480
+ self._users[key] = principal
1481
+ return principal
167
1482
 
168
1483
  def close(self) -> None:
169
1484
  pass
170
1485
 
171
1486
 
172
1487
  class SharePointListTarget:
173
- """Imports record payloads into a SharePoint list via ``from_records``."""
1488
+ """Imports record payloads into a SharePoint list.
174
1489
 
175
- def __init__(self, target_list: "SPList") -> None:
1490
+ Pass ``key`` (one or more natural-key columns) to make the target idempotent:
1491
+ a hash of those columns is stored in ``key_field`` and each payload is created
1492
+ or (``on_conflict="update"``) updated, so re-runs never duplicate. Without a
1493
+ key, records are appended and idempotency relies on the checkpoint/manifest.
1494
+
1495
+ ``on_conflict`` may be passed explicitly; otherwise it is derived from
1496
+ ``MigrationOptions.conflict_resolution`` by :meth:`configure` (the runner calls
1497
+ it before writes): ``OVERWRITE`` → ``"update"``, anything else → ``"skip"``.
1498
+
1499
+ Every migrated item also gets a source-id marker (``identity_field``, default
1500
+ ``MigrationSourceId``): the default ``SKIP`` policy then recognizes items already
1501
+ on the target (so re-runs do not duplicate) and :meth:`list_paths` pairs source
1502
+ and target items for verification. Pass ``identity_field=None`` to opt out.
1503
+ List-item attachments are written after their parent records are flushed.
1504
+
1505
+ Pass ``content_type_map`` (a :class:`~office365.migration.map.ContentTypeMap`)
1506
+ when the target list's content types were recreated with fresh identifiers:
1507
+ every record's ``ContentTypeId`` is rewritten to the target id so items land
1508
+ under the recreated content type instead of the wrong (or a missing) one.
1509
+ """
1510
+
1511
+ # Marks this target as accepting list-item attachments as extra items (see DataTarget).
1512
+ supports_attachments = True
1513
+
1514
+ # Marks this target as remapping Lookup values across migrated lists and Person
1515
+ # values by login (see ``_remap_typed_values``).
1516
+ supports_typed_values = True
1517
+
1518
+ # Marks this target as replaying a list item's approval state (``_ModerationStatus``
1519
+ # and its comments) in the metadata write, which a system update would otherwise
1520
+ # reset. Check-out and draft-version state are still not carried.
1521
+ supports_item_state = True
1522
+
1523
+ #: The single-item :meth:`write` only queues a create; a chunk must be flushed
1524
+ #: before it is durable. The runner therefore routes this target through the
1525
+ #: chunked path even at ``concurrency == 1``, so checkpoints never record
1526
+ #: ``DONE`` ahead of the actual write.
1527
+ deferred_writes = True
1528
+
1529
+ def rebind(self) -> "SharePointListTarget":
1530
+ """This target on its own cloned context (see :meth:`SharePointListSource.rebind`)."""
1531
+ return SharePointListTarget(
1532
+ _cloned_list(self._list),
1533
+ key=list(self._key_columns) or None,
1534
+ key_field=self._key_field,
1535
+ on_conflict=self._on_conflict_override,
1536
+ identity_field=self._identity_field,
1537
+ content_type_map=self._content_type_map,
1538
+ )
1539
+
1540
+ def __init__(
1541
+ self,
1542
+ target_list: "SPList",
1543
+ key: str | list[str] | None = None,
1544
+ key_field: str = "MigrationKey",
1545
+ on_conflict: str | None = None,
1546
+ identity_field: str | None = DEFAULT_LIST_IDENTITY_FIELD,
1547
+ content_type_map: "ContentTypeMap | None" = None,
1548
+ ) -> None:
176
1549
  self._list = target_list
1550
+ self._key_columns = [key] if isinstance(key, str) else (list(key) if key else [])
1551
+ self._key_field = key_field
1552
+ self._on_conflict_override = on_conflict
1553
+ self._on_conflict = on_conflict or "skip"
1554
+ self._target = None
1555
+ self._existing: dict = {}
1556
+ self._identity_field = identity_field
1557
+ self._identity_ensured = False
1558
+ self._identity_index: dict | None = None
1559
+ self._identity_index_stale = False
1560
+ self._identity_index_max_id = 0
1561
+ self._attachment_path_cache: set[str] | None = None
1562
+ self._content_type_map = content_type_map
1563
+ self._login_cache: dict[int, str | None] = {}
1564
+ # Author/Editor values already written by ``apply_authorship`` but pending a
1565
+ # shared final write (see ``apply_timestamps``); avoids the ValidateUpdateListItem
1566
+ # call that restores timestamps silently resetting ``Editor`` to the caller.
1567
+ self._pending_authorship: dict[str, dict] = {}
1568
+ # Approval state read from the payload, replayed in the metadata write (a
1569
+ # system update approves the item); same pending-then-pop lifecycle as above.
1570
+ self._pending_approval: dict[str, dict[str, str]] = {}
1571
+ self.warnings: list[str] = []
1572
+ self._principals_cache: _TargetPrincipals | None = None
1573
+ # Lookup and Person columns carry an id that is only meaningful on the
1574
+ # source (list-local item id / site-user id). The target remaps each to its
1575
+ # own value on write and back to the source value on verification.
1576
+ self._columns_cache: _TypedColumns | None = None
1577
+ self._lookup_indexes: dict[str, tuple[dict[int, int], dict[int, int]]] = {}
1578
+ self._unresolved_lookups: set[tuple[str, int]] = set()
1579
+ self._unresolved_users: set[tuple[str, str]] = set()
1580
+ self._user_logins: dict[int, str] | None = None
1581
+
1582
+ @property
1583
+ def on_conflict(self) -> str:
1584
+ """The active record conflict policy (``"skip"`` or ``"update"``)."""
1585
+ return self._on_conflict
1586
+
1587
+ def configure(self, options) -> None:
1588
+ """Derive ``on_conflict`` from ``MigrationOptions.conflict_resolution``.
1589
+
1590
+ Called by :class:`MigrationRunner` before the run, so a single
1591
+ ``conflict_resolution`` drives both file and record targets. An
1592
+ ``on_conflict`` passed to the constructor is honored as-is.
1593
+ """
1594
+ if self._on_conflict_override is None:
1595
+ self._on_conflict = conflict_to_on_conflict(options.conflict_resolution)
177
1596
 
178
1597
  def label(self) -> str:
179
1598
  return f"list:{self._list.title}"
180
1599
 
181
1600
  def exists(self, item: MigrationItem) -> bool:
182
- return False # records are appended; idempotency via manifest/checkpoint
1601
+ # With the identity marker, both records and attachments are recognized on a
1602
+ # re-run, so the default ``SKIP`` policy is genuinely idempotent. Without it
1603
+ # (``identity_field=None``) nothing is recognized and records append.
1604
+ if not self._identity_field:
1605
+ return False
1606
+ self._ensure_identity()
1607
+ if not self._identity_field:
1608
+ return False
1609
+ if item.item_type == "attachment":
1610
+ return str(item.dest_path) in set(self._attachment_paths())
1611
+ return self._find_by_identity(item.dest_path) is not None
183
1612
 
184
1613
  def write(self, item: MigrationItem, payload: object) -> None:
185
- self._list.items.from_records([cast(dict, payload)])
1614
+ if item.item_type == "attachment":
1615
+ self._write_attachment(item, payload)
1616
+ return
1617
+ self._queue([self._record_for(item, payload)])
1618
+
1619
+ def write_many(
1620
+ self,
1621
+ items: list[MigrationItem],
1622
+ payloads: list[object],
1623
+ concurrency: int = 1,
1624
+ ) -> list[Failure]:
1625
+ """Queue a chunk and flush it immediately, then discard the entities.
1626
+
1627
+ Flushing per chunk (instead of only at :meth:`commit`) keeps a large list
1628
+ migration memory-bounded — the queued creates never accumulate for the
1629
+ whole run. Attachments in the chunk are written after its records are
1630
+ flushed, so their parent items already exist.
1631
+
1632
+ Returns:
1633
+ No failures (a batch failure raises; there are no partial successes).
1634
+ """
1635
+ records: list[dict] = []
1636
+ attachments: list[tuple[MigrationItem, object]] = []
1637
+ for item, payload in zip(items, payloads):
1638
+ if item.item_type == "attachment":
1639
+ attachments.append((item, payload))
1640
+ else:
1641
+ records.append(self._record_for(item, payload))
1642
+ if records:
1643
+ self._queue(records)
1644
+ self._flush(len(records), concurrency)
1645
+ for item, payload in attachments:
1646
+ self._write_attachment(item, payload)
1647
+ return []
1648
+
1649
+ def _record_for(self, item: MigrationItem, payload: object) -> dict:
1650
+ """The payload with the target content-type id and source-id marker applied."""
1651
+ record = dict(cast(dict, payload))
1652
+ if self._content_type_map:
1653
+ content_type_id = record.get("ContentTypeId")
1654
+ record["ContentTypeId"] = self._content_type_map.resolve(content_type_id)
1655
+ if self._identity_field:
1656
+ record[self._identity_field] = item.dest_path
1657
+ approval = {
1658
+ field_name: str(record[record_key])
1659
+ for record_key, field_name in _APPROVAL_FIELDS.items()
1660
+ if record.get(record_key) is not None
1661
+ }
1662
+ if approval:
1663
+ self._pending_approval[item.dest_path] = approval
1664
+ return record
1665
+
1666
+ def translate_record(self, record: dict) -> dict:
1667
+ """A source record mapped onto this list without writing it.
1668
+
1669
+ A document library folder is a list item that already exists on the target,
1670
+ so its column values cannot go through the create queue: the record is mapped
1671
+ here (target content-type id, Lookup ids, Person logins, multi-value shapes)
1672
+ and applied with an update instead.
1673
+ """
1674
+ mapped = dict(record)
1675
+ if self._content_type_map:
1676
+ resolved = self._content_type_map.resolve(mapped.get("ContentTypeId"))
1677
+ if resolved:
1678
+ mapped["ContentTypeId"] = resolved
1679
+ else:
1680
+ mapped.pop("ContentTypeId", None)
1681
+ self._remap_typed_values([mapped])
1682
+ return mapped
1683
+
1684
+ def _queue(self, records: list[dict]) -> None:
1685
+ self._ensure_identity()
1686
+ self._remap_typed_values(records)
1687
+ if not self._key_columns:
1688
+ for record in records:
1689
+ self._list.items.queue_records([self._multi_value_create(record)])
1690
+ return
1691
+ from office365.runtime.converters.upsert import keyed_queue
1692
+ from office365.sharepoint.fields.name import internal_field_name
1693
+
1694
+ target = self._target
1695
+ if target is None:
1696
+ target = self._list.items.upsert_target(key_field=self._key_field)
1697
+ target.ensure_key_field()
1698
+ self._list.context.execute_query()
1699
+ self._existing.update(target.load_keys())
1700
+ self._target = target
1701
+ key_columns = [internal_field_name(c) for c in self._key_columns]
1702
+ keyed_queue(
1703
+ _MultiValueCreateTarget(target, self._multi_value_create),
1704
+ records,
1705
+ key_columns=key_columns,
1706
+ existing=self._existing,
1707
+ on_conflict=self._on_conflict,
1708
+ )
1709
+
1710
+ def _multi_id_keys(self) -> set[str]:
1711
+ """The ``...Id`` record keys of the multi-value Lookup/Person columns."""
1712
+ names = (*self._multi_lookup_columns(), *self._multi_user_columns())
1713
+ return {f"{name}Id" for name in names}
1714
+
1715
+ def _multi_value_create(self, record: dict) -> dict:
1716
+ """Reshape multi-value columns for a *create* (``{"results": [...]}``).
1717
+
1718
+ A bare list is the semantic value the source records and the checksum work
1719
+ with, and it is also what a MERGE update wants; only a create needs the
1720
+ ``{"results": [...]}`` wrapper (live-probed). Lists without multi-value
1721
+ columns are passed through untouched.
1722
+ """
1723
+ keys = self._multi_id_keys() | self._multi_choice_columns()
1724
+ if not keys:
1725
+ return record
1726
+ wrapped = dict(record)
1727
+ for key in keys:
1728
+ values = _multi_values(wrapped.get(key))
1729
+ if values is not None:
1730
+ wrapped[key] = _collection_payload(values)
1731
+ return wrapped
1732
+
1733
+ def _ensure_identity(self) -> None:
1734
+ """Create the source-id marker column (once), best-effort."""
1735
+ if self._identity_ensured or not self._identity_field:
1736
+ return
1737
+ self._identity_ensured = True
1738
+ name = self._identity_field
1739
+ from office365.sharepoint.fields.creation_information import FieldCreationInformation
1740
+ from office365.sharepoint.fields.type import FieldType
1741
+
1742
+ try:
1743
+ self._list.fields.ensure(FieldCreationInformation(name, FieldType.Text)).execute_query()
1744
+ except Exception as e: # noqa: BLE001 — identity is best-effort; content still migrates
1745
+ self._identity_field = None
1746
+ self.warnings.append(f"could not create the {name!r} identity column: {e}")
1747
+
1748
+ def _columns(self) -> _TypedColumns:
1749
+ """The target's typed columns.
1750
+
1751
+ Returns ``(lookup: name -> referenced list id, user names, multi-lookup:
1752
+ name -> referenced list id, multi-user names, taxonomy: name -> (allows
1753
+ many, hidden note field internal name), multi-choice names)``.
1754
+ """
1755
+ if self._columns_cache is None:
1756
+ self._columns_cache = self._load_columns()
1757
+ return self._columns_cache
1758
+
1759
+ def _lookup_columns(self) -> dict[str, str]:
1760
+ return self._columns()[0]
1761
+
1762
+ def _user_columns(self) -> set[str]:
1763
+ return self._columns()[1]
1764
+
1765
+ def _multi_lookup_columns(self) -> dict[str, str]:
1766
+ return self._columns()[2]
1767
+
1768
+ def _multi_user_columns(self) -> set[str]:
1769
+ return self._columns()[3]
1770
+
1771
+ def _taxonomy_columns(self) -> dict[str, tuple[bool, str | None]]:
1772
+ return self._columns()[4]
1773
+
1774
+ def _multi_choice_columns(self) -> set[str]:
1775
+ return self._columns()[5]
1776
+
1777
+ def _load_columns(self) -> _TypedColumns:
1778
+ lookups: dict[str, str] = {}
1779
+ users: set[str] = set()
1780
+ multi_lookups: dict[str, str] = {}
1781
+ multi_users: set[str] = set()
1782
+ taxonomy: dict[str, tuple[bool, str | None]] = {}
1783
+ multi_choices: set[str] = set()
1784
+ try:
1785
+ fields = (
1786
+ self._list.fields.select(
1787
+ ["InternalName", "TypeAsString", "LookupList", "Id", "TextField", "AllowMultipleValues"]
1788
+ )
1789
+ .get()
1790
+ .execute_query()
1791
+ )
1792
+ except Exception as e: # noqa: BLE001 — without columns we cannot remap; content still migrates
1793
+ self.warnings.append(f"could not read target columns for typed-value remapping: {e}")
1794
+ return lookups, users, multi_lookups, multi_users, taxonomy, multi_choices
1795
+ by_id = {normalize_guid(getattr(field, "id", None)): getattr(field, "internal_name", None) for field in fields}
1796
+ for field in fields:
1797
+ internal_name = getattr(field, "internal_name", None)
1798
+ if not internal_name or internal_name in _PERSON_EXCLUDED:
1799
+ continue
1800
+ field_type = getattr(field, "type_as_string", None)
1801
+ if field_type in _TAXONOMY_FIELD_TYPES:
1802
+ # The companion note column that actually carries the write payload
1803
+ # has an unpredictable name; resolve it through the column's
1804
+ # ``TextField`` id.
1805
+ note_name = by_id.get(normalize_guid(field.properties.get("TextField")))
1806
+ taxonomy[internal_name] = (field_type == "TaxonomyFieldTypeMulti", note_name)
1807
+ elif field_type in _TYPED_VALUE_TYPES:
1808
+ multiple = _allows_multiple_values(field)
1809
+ if field_type.startswith("User"):
1810
+ if multiple:
1811
+ multi_users.add(internal_name)
1812
+ else:
1813
+ users.add(internal_name)
1814
+ else:
1815
+ list_id = normalize_guid(field.properties.get("LookupList"))
1816
+ if not list_id:
1817
+ continue
1818
+ if multiple:
1819
+ multi_lookups[internal_name] = list_id
1820
+ else:
1821
+ lookups[internal_name] = list_id
1822
+ elif _is_multi_choice_column(field):
1823
+ multi_choices.add(internal_name)
1824
+ return lookups, users, multi_lookups, multi_users, taxonomy, multi_choices
1825
+
1826
+ def _lookup_index(self, target_list_id: str) -> tuple[dict[int, int], dict[int, int]]:
1827
+ """``(source id -> target id, target id -> source id)`` for a referenced list."""
1828
+ cached = self._lookup_indexes.get(target_list_id)
1829
+ if cached is not None:
1830
+ return cached
1831
+ forward: dict[int, int] = {}
1832
+ backward: dict[int, int] = {}
1833
+ self._flush_pending()
1834
+ try:
1835
+ referenced = self._list.context.web.lists.get_by_id(target_list_id)
1836
+ items = referenced.items.select(["Id", DEFAULT_LIST_IDENTITY_FIELD]).get_all().execute_query()
1837
+ except Exception as e: # noqa: BLE001 — an unreadable referenced list is reported, not fatal
1838
+ self.warnings.append(f"lookup target list {target_list_id} could not be read: {e}")
1839
+ items = []
1840
+ for referenced_item in items:
1841
+ source_id = parse_int(referenced_item.properties.get(DEFAULT_LIST_IDENTITY_FIELD))
1842
+ target_id = parse_int(referenced_item.id)
1843
+ if source_id is None or target_id is None:
1844
+ continue
1845
+ forward[source_id] = target_id
1846
+ backward[target_id] = source_id
1847
+ self._lookup_indexes[target_list_id] = (forward, backward)
1848
+ return forward, backward
1849
+
1850
+ def _remap_typed_values(self, records: list[dict]) -> None:
1851
+ """Translate each record's source lookup/person ids into target values.
1852
+
1853
+ A lookup references another migrated list (matched on its items' source-id
1854
+ marker); a person carries the *login name* the source annotated, resolved
1855
+ here with ``EnsureUser``. Either value with no match is dropped and reported
1856
+ once rather than written as a wrong id.
1857
+ """
1858
+ self._remap_lookups(records)
1859
+ self._remap_users(records)
1860
+ self._remap_multi_lookups(records)
1861
+ self._remap_multi_users(records)
1862
+ self._remap_taxonomies(records)
1863
+
1864
+ def _remap_lookups(self, records: list[dict]) -> None:
1865
+ columns = self._lookup_columns()
1866
+ if not columns:
1867
+ return
1868
+ for record in records:
1869
+ for internal_name, target_list_id in columns.items():
1870
+ key = f"{internal_name}Id"
1871
+ source_id = parse_int(record.get(key))
1872
+ if source_id is None:
1873
+ continue
1874
+ forward, _ = self._lookup_index(target_list_id)
1875
+ target_id = forward.get(source_id)
1876
+ if target_id is None:
1877
+ record.pop(key, None)
1878
+ self._report_unresolved_lookup(internal_name, source_id)
1879
+ continue
1880
+ record[key] = target_id
1881
+
1882
+ def _remap_users(self, records: list[dict]) -> None:
1883
+ columns = self._user_columns()
1884
+ if not columns:
1885
+ return
1886
+ for record in records:
1887
+ for internal_name in columns:
1888
+ key = f"{internal_name}Id"
1889
+ login = record.get(key)
1890
+ if not isinstance(login, str) or not login:
1891
+ continue
1892
+ user = self._principals().user(login)
1893
+ if user is None or getattr(user, "id", None) is None:
1894
+ record.pop(key, None)
1895
+ self._report_unresolved_user(internal_name, login)
1896
+ continue
1897
+ record[key] = user.id
1898
+
1899
+ def _remap_multi_lookups(self, records: list[dict]) -> None:
1900
+ columns = self._multi_lookup_columns()
1901
+ if not columns:
1902
+ return
1903
+ for record in records:
1904
+ for internal_name, target_list_id in columns.items():
1905
+ key = f"{internal_name}Id"
1906
+ source_ids = _id_list(record.get(key))
1907
+ if not source_ids:
1908
+ continue
1909
+ forward, _ = self._lookup_index(target_list_id)
1910
+ target_ids: list[int] = []
1911
+ for value in source_ids:
1912
+ source_id = parse_int(value)
1913
+ target_id = forward.get(source_id) if source_id is not None else None
1914
+ if target_id is None:
1915
+ if source_id is not None:
1916
+ self._report_unresolved_lookup(internal_name, source_id)
1917
+ continue
1918
+ target_ids.append(target_id)
1919
+ if target_ids:
1920
+ record[key] = target_ids
1921
+ else:
1922
+ record.pop(key, None)
1923
+
1924
+ def _remap_multi_users(self, records: list[dict]) -> None:
1925
+ columns = self._multi_user_columns()
1926
+ if not columns:
1927
+ return
1928
+ for record in records:
1929
+ for internal_name in columns:
1930
+ key = f"{internal_name}Id"
1931
+ logins = record.get(key)
1932
+ if not isinstance(logins, (list, tuple)) or not logins:
1933
+ continue
1934
+ target_ids: list[int] = []
1935
+ for login in logins:
1936
+ user = self._principals().user(login) if isinstance(login, str) and login else None
1937
+ user_id = getattr(user, "id", None)
1938
+ if user is None or user_id is None:
1939
+ self._report_unresolved_user(internal_name, str(login))
1940
+ continue
1941
+ target_ids.append(user_id)
1942
+ if target_ids:
1943
+ record[key] = target_ids
1944
+ else:
1945
+ record.pop(key, None)
1946
+
1947
+ def _remap_taxonomies(self, records: list[dict]) -> None:
1948
+ """Write taxonomy terms in the form SharePoint accepts on the target.
1949
+
1950
+ A single-value column takes a typed ``SP.Taxonomy.TaxonomyFieldValue``
1951
+ object; a multi-value column only accepts the hidden note companion's text
1952
+ form ``-1;#Label|guid;#...`` (typed-collection JSON is rejected server-side).
1953
+ The term id is authoritative — the label can be left blank. A column with no
1954
+ target counterpart is dropped and reported rather than sent as an unknown
1955
+ property.
1956
+ """
1957
+ columns = self._taxonomy_columns()
1958
+ unresolved: set[str] = set()
1959
+ for record in records:
1960
+ for internal_name, value in list(record.items()):
1961
+ if not _is_taxonomy_value(value):
1962
+ continue
1963
+ guids = _taxonomy_guids(value)
1964
+ column = columns.get(internal_name)
1965
+ if column is None:
1966
+ record.pop(internal_name, None)
1967
+ unresolved.add(internal_name)
1968
+ continue
1969
+ allow_many, note_name = column
1970
+ if not guids:
1971
+ record.pop(internal_name, None)
1972
+ continue
1973
+ if allow_many and note_name:
1974
+ record.pop(internal_name, None)
1975
+ record[note_name] = ";#".join(f"-1;#|{guid}" for guid in guids)
1976
+ elif allow_many:
1977
+ record.pop(internal_name, None)
1978
+ unresolved.add(internal_name)
1979
+ else:
1980
+ record[internal_name] = {
1981
+ "__metadata": {"type": "SP.Taxonomy.TaxonomyFieldValue"},
1982
+ "Label": "",
1983
+ "TermGuid": guids[0],
1984
+ "WssId": -1,
1985
+ }
1986
+ if unresolved:
1987
+ self.warnings.append(
1988
+ f"taxonomy column(s) not available on the target, values left empty: {', '.join(sorted(unresolved))}"
1989
+ )
1990
+
1991
+ def _report_unresolved_user(self, internal_name: str, login: str) -> None:
1992
+ marker = (internal_name, login)
1993
+ if marker in self._unresolved_users:
1994
+ return
1995
+ self._unresolved_users.add(marker)
1996
+ self.warnings.append(
1997
+ f"person column '{internal_name}' login {login!r} could not be resolved on the target; "
1998
+ "the value was left empty"
1999
+ )
2000
+
2001
+ def _target_user_logins(self) -> dict[int, str]:
2002
+ """The target web's ``{site-user id: login name}`` map (cached)."""
2003
+ if self._user_logins is None:
2004
+ mapping: dict[int, str] = {}
2005
+ try:
2006
+ for site_user in self._list.context.web.site_users.get().execute_query():
2007
+ user_id = parse_int(site_user.id)
2008
+ if user_id is not None and site_user.login_name:
2009
+ mapping[user_id] = site_user.login_name
2010
+ except Exception as e: # noqa: BLE001 — without the map persons are left as ids
2011
+ self.warnings.append(f"could not read target site users for person verification: {e}")
2012
+ self._user_logins = mapping
2013
+ return self._user_logins
2014
+
2015
+ def _report_unresolved_lookup(self, internal_name: str, source_id: int) -> None:
2016
+ marker = (internal_name, source_id)
2017
+ if marker in self._unresolved_lookups:
2018
+ return
2019
+ self._unresolved_lookups.add(marker)
2020
+ self.warnings.append(
2021
+ f"lookup column '{internal_name}' value {source_id} could not be mapped to a target item "
2022
+ "(the referenced list's items were not migrated first); the value was left empty"
2023
+ )
2024
+
2025
+ def _canonicalize_lookups(self, properties: dict) -> None:
2026
+ """Rewrite target lookup ids back to the source ids (symmetric to the write).
2027
+
2028
+ The source checksum holds the source item id; the target's fresh item holds
2029
+ the target id. Mapping the latter back lets the content spot-check compare
2030
+ the two like for like instead of reporting a false mismatch.
2031
+ """
2032
+ for internal_name, target_list_id in self._lookup_columns().items():
2033
+ key = f"{internal_name}Id"
2034
+ target_id = parse_int(properties.get(key))
2035
+ if target_id is None:
2036
+ continue
2037
+ _, backward = self._lookup_index(target_list_id)
2038
+ source_id = backward.get(target_id)
2039
+ if source_id is not None:
2040
+ properties[key] = source_id
2041
+ for internal_name, target_list_id in self._multi_lookup_columns().items():
2042
+ key = f"{internal_name}Id"
2043
+ target_ids = _id_list(properties.get(key))
2044
+ if not target_ids:
2045
+ continue
2046
+ _, backward = self._lookup_index(target_list_id)
2047
+ mapped: list[Any] = []
2048
+ for value in target_ids:
2049
+ target_id = parse_int(value)
2050
+ mapped.append(backward.get(target_id, value) if target_id is not None else value)
2051
+ properties[key] = mapped
2052
+
2053
+ def _canonicalize_users(self, properties: dict) -> None:
2054
+ """Rewrite target person ids back to the login names the source recorded."""
2055
+ columns = self._user_columns()
2056
+ logins = self._target_user_logins() if columns or self._multi_user_columns() else {}
2057
+ for internal_name in columns:
2058
+ key = f"{internal_name}Id"
2059
+ user_id = parse_int(properties.get(key))
2060
+ if user_id is None:
2061
+ continue
2062
+ login = logins.get(user_id)
2063
+ if login is not None:
2064
+ properties[key] = login
2065
+ for internal_name in self._multi_user_columns():
2066
+ key = f"{internal_name}Id"
2067
+ user_ids = _id_list(properties.get(key))
2068
+ if not user_ids:
2069
+ continue
2070
+ mapped_logins: list[Any] = []
2071
+ for value in user_ids:
2072
+ user_id = parse_int(value)
2073
+ mapped_logins.append(logins.get(user_id, value) if user_id is not None else value)
2074
+ properties[key] = mapped_logins
2075
+
2076
+ def _canonicalize_multi_choices(self, properties: dict) -> None:
2077
+ """Reduce a read-back multi-choice cell to the bare list the source records.
2078
+
2079
+ A live read returns the selected values as a positional mapping
2080
+ (``{0: "red", 1: "green"}``); the source checksum holds a bare list, so the
2081
+ two are only comparable after the same projection.
2082
+ """
2083
+ for internal_name in self._multi_choice_columns():
2084
+ if internal_name not in properties:
2085
+ continue
2086
+ values = _multi_values(properties.get(internal_name))
2087
+ if values:
2088
+ properties[internal_name] = values
2089
+ else:
2090
+ properties.pop(internal_name, None)
2091
+
2092
+ def _write_attachment(self, item: MigrationItem, payload: object) -> None:
2093
+ if not self._identity_field:
2094
+ raise NotImplementedError("attachments need the identity column, which could not be created")
2095
+ parent_id, _, filename = str(item.dest_path).partition("/")
2096
+ if not filename:
2097
+ raise ValueError(f"invalid attachment destination {item.dest_path!r}")
2098
+ self._flush_pending()
2099
+ parent = self._find_by_identity(parent_id)
2100
+ if parent is None:
2101
+ raise ValueError(f"no target item for source id {parent_id!r}; cannot attach {filename!r}")
2102
+ content = payload if isinstance(payload, bytes) else str(payload).encode("utf-8")
2103
+ parent.attachment_files.add({"filename": filename, "content": content}).execute_query()
2104
+ if self._attachment_path_cache is not None:
2105
+ self._attachment_path_cache.add(str(item.dest_path))
2106
+
2107
+ def _flush_pending(self) -> None:
2108
+ if self._list.context.has_pending_request:
2109
+ self._flush(DEFAULT_BATCH_SIZE, 1)
2110
+
2111
+ def _find_by_identity(self, source_id: str):
2112
+ if self._identity_index is None or self._identity_index_stale:
2113
+ self._refresh_identity_index()
2114
+ return self._identity_index.get(str(source_id)) if self._identity_index else None
2115
+
2116
+ def _refresh_identity_index(self) -> None:
2117
+ """Load, or incrementally extend, the source-id -> target item map.
2118
+
2119
+ After a chunk is flushed only the newly created items are re-read
2120
+ (``Id gt <max>``) instead of re-scanning the whole list, so refreshing the
2121
+ index per chunk stays linear rather than O(n²).
2122
+ """
2123
+ if not self._identity_field:
2124
+ self._identity_index = {}
2125
+ return
2126
+ if self._identity_index is not None and self._identity_index_max_id > 0:
2127
+ self._index_identity_items(self._query_identity_items(f"Id gt {self._identity_index_max_id}"))
2128
+ return
2129
+ self._identity_index = {}
2130
+ self._identity_index_max_id = 0
2131
+ self._index_identity_items(self._query_identity_items())
2132
+
2133
+ def _query_identity_items(self, filter_expr: str | None = None):
2134
+ # A read query would implicitly flush any queued writes on this context;
2135
+ # flush them explicitly first so the cached index stays consistent.
2136
+ self._flush_pending()
2137
+ columns = ["Id", self._identity_field, "Created", "Modified", "AuthorId", "EditorId"]
2138
+ query = self._list.items.select(columns)
2139
+ if filter_expr:
2140
+ query = query.filter(filter_expr)
2141
+ return query.get_all().execute_query()
2142
+
2143
+ def _index_identity_items(self, items) -> None:
2144
+ if self._identity_index is None:
2145
+ self._identity_index = {}
2146
+ for target_item in items:
2147
+ value = target_item.properties.get(self._identity_field)
2148
+ if value is None:
2149
+ continue
2150
+ self._identity_index[str(value)] = target_item
2151
+ item_id = parse_int(getattr(target_item, "id", None))
2152
+ if item_id is not None and item_id > self._identity_index_max_id:
2153
+ self._identity_index_max_id = item_id
2154
+ self._identity_index_stale = False
2155
+
2156
+ def _attachment_paths(self) -> list[str]:
2157
+ if not self._identity_field:
2158
+ return []
2159
+ if self._attachment_path_cache is None:
2160
+ self._attachment_path_cache = set(self._query_attachment_paths())
2161
+ return list(self._attachment_path_cache)
2162
+
2163
+ def _query_attachment_paths(self) -> list[str]:
2164
+ if not self._identity_field:
2165
+ return []
2166
+ self._flush_pending()
2167
+ items = (
2168
+ self._list.items.select(["Id", self._identity_field]).expand(["AttachmentFiles"]).get_all().execute_query()
2169
+ )
2170
+ paths: list[str] = []
2171
+ for target_item in items:
2172
+ value = target_item.properties.get(self._identity_field)
2173
+ if value is None:
2174
+ continue
2175
+ for attachment in target_item.properties.get("AttachmentFiles") or []:
2176
+ name = getattr(attachment, "file_name", None)
2177
+ if name:
2178
+ paths.append(f"{value}/{name}")
2179
+ return paths
186
2180
 
187
2181
  def list_paths(self) -> list[str]:
188
- return [str(i.id) for i in self._list.items.get().execute_query()]
2182
+ if not self._identity_field:
2183
+ return [str(i.id) for i in self._list.items.get().execute_query()]
2184
+ # An empty source list never queues a write, so the marker column was not
2185
+ # created during migration; ensure it before verification queries it.
2186
+ self._ensure_identity()
2187
+ if not self._identity_field:
2188
+ return [str(i.id) for i in self._list.items.get().execute_query()]
2189
+ if self._identity_index is None or self._identity_index_stale:
2190
+ self._refresh_identity_index()
2191
+ index = self._identity_index or {}
2192
+ return list(index.keys()) + self._attachment_paths()
189
2193
 
190
2194
  def checksum(self, item: MigrationItem) -> str:
191
- return ""
2195
+ if item.item_type == "attachment":
2196
+ return self._attachment_checksum(item)
2197
+ target_item = self._fresh_target_item(item)
2198
+ if target_item is None:
2199
+ return ""
2200
+ return self.content_checksum(dict(target_item.properties))
2201
+
2202
+ def content_checksum(self, properties: dict) -> str:
2203
+ """The comparable content hash of an item's read-back properties.
2204
+
2205
+ Used for both a written record and a folder's item, so a library folder's
2206
+ column values can be reconciled against the source record that produced them.
2207
+ """
2208
+ properties = _canonicalize_taxonomy_record(dict(properties))
2209
+ self._canonicalize_lookups(properties)
2210
+ self._canonicalize_users(properties)
2211
+ self._canonicalize_multi_choices(properties)
2212
+ extra = {self._identity_field} if self._identity_field else set()
2213
+ # The hidden taxonomy note companion is not part of the source's portable
2214
+ # content; it is verified through the term ids on the column itself.
2215
+ extra.update(note for _, note in self._taxonomy_columns().values() if note)
2216
+ # The target derives its own ``<name>StringId`` companion; it is not part of
2217
+ # the source's canonical content.
2218
+ extra.update(f"{name}StringId" for name in self._user_columns())
2219
+ extra.update(f"{name}StringId" for name in self._multi_user_columns())
2220
+ return _content_checksum(properties, frozenset(extra))
2221
+
2222
+ def _attachment_checksum(self, item: MigrationItem) -> str:
2223
+ parent_id, _, filename = str(item.dest_path).partition("/")
2224
+ parent = self._find_by_identity(parent_id)
2225
+ if parent is None:
2226
+ return ""
2227
+ try:
2228
+ data = parent.attachment_files.get_by_filename(filename).get_content().execute_query().value
2229
+ except Exception: # noqa: BLE001 — a missing/unreadable attachment is unverifiable
2230
+ return ""
2231
+ return hashlib.md5(data).hexdigest() if data else ""
192
2232
 
193
2233
  def commit(self, options=None) -> None:
194
- """Flush the queued record writes through an OData batch (JSON-only parallel mode)."""
195
- batch_size = getattr(options, "batch_size", None) or 100
2234
+ """Flush any remaining queued record writes through an OData batch."""
2235
+ batch_size = getattr(options, "batch_size", None) or DEFAULT_BATCH_SIZE
196
2236
  concurrency = getattr(options, "concurrency", None) or 1
2237
+ self._flush(batch_size, concurrency)
2238
+ self._pending_authorship.clear()
2239
+ self._pending_approval.clear()
2240
+
2241
+ def _flush(self, batch_size: int, concurrency: int) -> None:
2242
+ if not self._list.context.has_pending_request:
2243
+ return
197
2244
  self._list.context.execute_batch(items_per_batch=batch_size, concurrency=concurrency)
2245
+ self._list.items.clear()
2246
+ # Records were just created/updated, so the cached source-id index needs an
2247
+ # incremental refresh (new items only) before the next lookup.
2248
+ if self._identity_index is not None:
2249
+ self._identity_index_stale = True
2250
+
2251
+ def _principals(self) -> _TargetPrincipals:
2252
+ """The (lazily built) target principal/role resolver."""
2253
+ if self._principals_cache is None:
2254
+ self._principals_cache = _TargetPrincipals(self._list.context.web, self.warnings)
2255
+ return self._principals_cache
2256
+
2257
+ def _target_item(self, item: MigrationItem):
2258
+ """The written target item for a record (``None`` for attachments/folders)."""
2259
+ if item.item_type == "attachment":
2260
+ return None
2261
+ return self._find_by_identity(item.dest_path)
2262
+
2263
+ def apply_timestamps(self, item: MigrationItem) -> None:
2264
+ """Best-effort: restore ``Created``/``Modified`` on the written item.
2265
+
2266
+ Uses ``ValidateUpdateListItem`` with ``bNewDocumentUpdate=True`` -- a
2267
+ system update (the CSOM ``UpdateOverwriteVersion`` path), so the metadata
2268
+ lands **without** creating a new version and a migrated record keeps its
2269
+ original version instead of accumulating one version per fidelity write.
2270
+ ``datesInUTC=True`` requires the ``...Z`` UTC form. Authorship values
2271
+ resolved for the same item are folded into this final write so both land
2272
+ atomically, in one system update.
2273
+ """
2274
+ target_item = self._target_item(item)
2275
+ if target_item is None:
2276
+ return
2277
+ form_values: dict = {}
2278
+ created = _sp_utc_timestamp(item.created)
2279
+ modified = _sp_utc_timestamp(item.modified)
2280
+ if created:
2281
+ form_values["Created"] = created
2282
+ if modified:
2283
+ form_values["Modified"] = modified
2284
+ form_values.update(self._pending_authorship.pop(item.dest_path, {}))
2285
+ form_values.update(self._pending_approval.pop(item.dest_path, {}))
2286
+ if form_values:
2287
+ result = target_item.validate_update_list_item(
2288
+ form_values, dates_in_utc=True, new_document_update=True
2289
+ ).execute_query()
2290
+ _report_rejected_fields(result, self.warnings, f"timestamps {item.dest_path}")
2291
+
2292
+ def apply_authorship(self, item: MigrationItem) -> None:
2293
+ """Best-effort: resolve ``Author``/``Editor`` and cache them for one write.
2294
+
2295
+ A principal is applied only when its login name resolves to a target user
2296
+ (``EnsureUser``); unresolved principals are skipped (same-tenant only).
2297
+
2298
+ Nothing is sent here. ``ValidateUpdateListItem`` is one request per call, so
2299
+ writing the resolved principals immediately and then again with the
2300
+ timestamps cost every preserved item two system updates. The values are
2301
+ cached and folded into the timestamps write, or written by
2302
+ :meth:`finalize_fidelity` when timestamps are not preserved.
2303
+ """
2304
+ target_item = self._target_item(item)
2305
+ if target_item is None:
2306
+ return
2307
+ author = self._principals().user(item.author.login_name if item.author else None)
2308
+ editor = self._principals().user(item.editor.login_name if item.editor else None)
2309
+ if author is not None and _is_system_principal(author):
2310
+ author = None
2311
+ if editor is not None and _is_system_principal(editor):
2312
+ editor = None
2313
+ if author is None and editor is None and not self._pending_approval.get(item.dest_path):
2314
+ return
2315
+ form_values: dict = {}
2316
+ if author is not None:
2317
+ form_values["Author"] = FieldUserValue(author.id, author.login_name)
2318
+ if editor is not None:
2319
+ form_values["Editor"] = FieldUserValue(editor.id, editor.login_name)
2320
+ # Replay the approval state here too: this write is itself a system update, so
2321
+ # on a run that restores authorship without timestamps it is the last one.
2322
+ form_values.update(self._pending_approval.get(item.dest_path, {}))
2323
+ self._pending_authorship[item.dest_path] = dict(form_values)
2324
+
2325
+ def finalize_fidelity(self, item: MigrationItem) -> None:
2326
+ """Write the fidelity values that were only cached for this item.
2327
+
2328
+ The last hook wins the write: with timestamps preserved that is
2329
+ :meth:`apply_timestamps`; without them it is this method, so the item still
2330
+ gets one system update instead of one per property group. It runs before
2331
+ the approval write, which has to stay last (a system update re-approves).
2332
+ """
2333
+ form_values = self._pending_authorship.pop(item.dest_path, {})
2334
+ form_values.update(self._pending_approval.pop(item.dest_path, {}))
2335
+ if not form_values:
2336
+ return
2337
+ target_item = self._target_item(item)
2338
+ if target_item is None:
2339
+ return
2340
+ result = target_item.validate_update_list_item(
2341
+ form_values, dates_in_utc=True, new_document_update=True
2342
+ ).execute_query()
2343
+ _report_rejected_fields(result, self.warnings, f"authorship {item.dest_path}")
2344
+
2345
+ def apply_permissions(self, item: MigrationItem, permissions: list[PermissionEntry]) -> None:
2346
+ """Best-effort: replay the source item's unique ACLs onto the target item.
2347
+
2348
+ Same-tenant only — cross-tenant identity mapping is out of scope. See
2349
+ :func:`_replay_role_assignments` for what happens to principals, roles and
2350
+ inheritance that cannot be resolved.
2351
+ """
2352
+ target_item = self._target_item(item)
2353
+ if target_item is None:
2354
+ return
2355
+ _replay_role_assignments(target_item, self._principals(), permissions, self.warnings, item.dest_path)
2356
+ self._list.context.execute_query()
2357
+
2358
+ def _fresh_target_item(self, item: MigrationItem):
2359
+ """The written target item with freshly-read properties (verification hooks).
2360
+
2361
+ The cached identity-index object predates the fidelity writes
2362
+ (``apply_timestamps``/``apply_authorship``), so re-read it before diffing.
2363
+ """
2364
+ target_item = self._target_item(item)
2365
+ if target_item is not None:
2366
+ target_item.get().execute_query()
2367
+ return target_item
2368
+
2369
+ def read_metadata(self, item: MigrationItem) -> dict | None:
2370
+ """Comparable attributes of the written item (for the metadata diff)."""
2371
+ target_item = self._fresh_target_item(item)
2372
+ if target_item is None:
2373
+ return None
2374
+ properties = target_item.properties
2375
+ return {
2376
+ "created": iso_or_none(properties.get("Created")),
2377
+ "modified": iso_or_none(properties.get("Modified")),
2378
+ }
2379
+
2380
+ def read_authorship(self, item: MigrationItem) -> tuple[str | None, str | None]:
2381
+ """The written item's author/editor login names (for the authorship diff)."""
2382
+ target_item = self._fresh_target_item(item)
2383
+ if target_item is None:
2384
+ return (None, None)
2385
+ properties = target_item.properties
2386
+ return (
2387
+ _user_login(self._list.context.web, properties.get("AuthorId"), self._login_cache),
2388
+ _user_login(self._list.context.web, properties.get("EditorId"), self._login_cache),
2389
+ )
2390
+
2391
+ def read_permissions(self, item: MigrationItem) -> list[PermissionEntry]:
2392
+ """Read the written item's *unique* role assignments (for the permission diff)."""
2393
+ target_item = self._fresh_target_item(item)
2394
+ if target_item is None or not _has_unique_role_assignments(target_item, refresh=True):
2395
+ return []
2396
+ return _read_role_assignments(target_item, normalize=self._principals().normalize)
198
2397
 
199
2398
  def close(self) -> None:
200
2399
  pass
@@ -204,16 +2403,46 @@ class SharePointLibrarySource:
204
2403
  """Enumerates a document library's files and folders (recursively) for migration.
205
2404
 
206
2405
  Folder entries (``item_type="folder"``, trailing ``/`` on the destination)
207
- preserve the folder structure — including **empty** folders — on the target.
2406
+ preserve the folder structure — including **empty** folders — on the target, and
2407
+ carry the folder's own column values (a document set's metadata, a managed
2408
+ folder's department) as their payload when the parent list is known.
208
2409
  """
209
2410
 
2411
+ def rebind(self) -> "SharePointLibrarySource":
2412
+ """This source on its own cloned context (see :meth:`SharePointListSource.rebind`)."""
2413
+ context = _cloned_context(self._folder)
2414
+ sp_list = _cloned_list(self._sp_list, context) if self._sp_list is not None else None
2415
+ return SharePointLibrarySource(_cloned_folder(self._folder, context), self.on_bytes, sp_list=sp_list)
2416
+
210
2417
  def __init__(
211
2418
  self,
212
2419
  library_folder: "Folder",
213
2420
  on_bytes: Callable[[int, int | None], None] | None = None,
2421
+ sp_list: "SPList | None" = None,
214
2422
  ) -> None:
215
2423
  self._folder = library_folder
2424
+ # The parent list, when known — author/editor ids (``AuthorId``/``EditorId``)
2425
+ # are not exposed on the ``File`` resource and must be read from its items.
2426
+ self._sp_list = sp_list
2427
+ # Folder column values come from the list's items and are projected exactly
2428
+ # like a record's (typed values normalized), so that code is reused here.
2429
+ self._list_source = SharePointListSource(sp_list) if sp_list is not None else None
2430
+ self._folder_payloads: dict[str, dict] | None = None
216
2431
  self._files: dict[str, "File"] = {}
2432
+ # Folder resources by library-relative path, so their own system metadata
2433
+ # (``TimeCreated``/``TimeLastModified``) can be diffed after the run.
2434
+ self._folders: dict[str, "Folder"] = {}
2435
+ self._users: dict[int, "Principal | None"] = {}
2436
+ self._default_groups: _DefaultGroups | None = None
2437
+ self._item_authors: dict[str, tuple[int | None, int | None]] | None = None
2438
+ self._item_unique: dict[str, bool] | None = None
2439
+ # Content-approval state by file URL, read alongside the author ids (only
2440
+ # when the library moderates).
2441
+ self._item_moderation: dict[str, dict] | None = None
2442
+ # Server-relative URLs of checked-out files, read alongside the author ids.
2443
+ self._item_checkout: set[str] | None = None
2444
+ self._moderation_on: bool | None = None
2445
+ self.warnings: list[str] = []
217
2446
  # Optional hook invoked while a file downloads: (bytes_read, file_size)
218
2447
  self.on_bytes = on_bytes
219
2448
 
@@ -229,8 +2458,10 @@ class SharePointLibrarySource:
229
2458
  self._folder.ensure_properties(["ServerRelativeUrl"]).execute_query()
230
2459
  root = self._folder.server_relative_url or ""
231
2460
  root = root.rstrip("/")
2461
+ extra = _site_assets_scaffolding(self._folder)
232
2462
  loaded_folders = self._folder.get_folders(recursive=True).execute_query()
233
2463
  loaded = self._folder.get_files(recursive=True).execute_query()
2464
+ authors = self._file_authors()
234
2465
 
235
2466
  def _rel(url: str) -> str:
236
2467
  return url[len(root) :].lstrip("/") if root else url.lstrip("/")
@@ -240,29 +2471,114 @@ class SharePointLibrarySource:
240
2471
  for folder in loaded_folders:
241
2472
  url = folder.server_relative_url or ""
242
2473
  rel = _rel(url)
243
- if not rel or rel in seen:
2474
+ if not rel or rel in seen or _is_system_path(rel, extra):
244
2475
  continue
245
2476
  seen.add(rel)
246
- result.append(MigrationItem(source_path=url, dest_path=f"{rel}/", item_type="folder"))
2477
+ self._folders[rel] = folder
2478
+ author_id, editor_id = authors.get(url, (None, None))
2479
+ folder_item = MigrationItem(
2480
+ source_path=url,
2481
+ dest_path=f"{rel}/",
2482
+ item_type="folder",
2483
+ modified=iso_or_none(folder.time_last_modified),
2484
+ created=iso_or_none(folder.time_created),
2485
+ author_id=author_id,
2486
+ editor_id=editor_id,
2487
+ )
2488
+ if author_id is not None:
2489
+ folder_item.author = self._principal_for(author_id)
2490
+ if editor_id is not None:
2491
+ folder_item.editor = self._principal_for(editor_id)
2492
+ result.append(folder_item)
247
2493
  emit_progress(progress, done=len(result), stage="planning", items=[folder])
248
2494
  for file in loaded:
249
2495
  url = file.server_relative_url or ""
250
2496
  rel = _rel(url)
2497
+ if _is_system_path(rel, extra):
2498
+ continue
251
2499
  self._files[rel] = file
252
- result.append(
253
- MigrationItem(
254
- source_path=url,
255
- dest_path=rel,
256
- size_bytes=file.length or 0,
257
- item_type="file",
258
- )
2500
+ author_id = parse_int(file.author.id)
2501
+ editor_id = parse_int(file.modified_by.id)
2502
+ if author_id is None and editor_id is None:
2503
+ author_id, editor_id = authors.get(url, (None, None))
2504
+ item = MigrationItem(
2505
+ source_path=url,
2506
+ dest_path=rel,
2507
+ size_bytes=file.length or 0,
2508
+ item_type="file",
2509
+ modified=iso_or_none(file.time_last_modified),
2510
+ created=iso_or_none(file.time_created),
2511
+ author_id=author_id,
2512
+ editor_id=editor_id,
2513
+ source_id=str(file.unique_id) if file.unique_id else None,
2514
+ version_label=file.ui_version_label,
259
2515
  )
2516
+ if author_id is not None:
2517
+ item.author = self._principal_for(author_id)
2518
+ if editor_id is not None:
2519
+ item.editor = self._principal_for(editor_id)
2520
+ result.append(item)
260
2521
  emit_progress(progress, done=len(result), stage="planning", items=[file])
2522
+ self._report_checkouts(result)
2523
+ self._report_drafts(result)
261
2524
  return result
262
2525
 
263
- def read(self, item: MigrationItem) -> bytes:
2526
+ def _report_checkouts(self, items: list[MigrationItem]) -> None:
2527
+ """Warn about files whose in-progress edits REST cannot see.
2528
+
2529
+ A checked-out file exposes its last **checked-in** content, so the copy is
2530
+ faithful to what the source returns while the author's pending edits stay
2531
+ behind. Verification cannot catch that — it compares the same read — so the
2532
+ loss is reported here instead of passing silently.
2533
+ """
2534
+ checkout = self._item_checkout or set()
2535
+ checked = sorted(item.dest_path for item in items if item.item_type != "folder" and item.source_path in checkout)
2536
+ if not checked:
2537
+ return
2538
+ shown = ", ".join(checked[:_WARNING_SAMPLE])
2539
+ if len(checked) > _WARNING_SAMPLE:
2540
+ shown = f"{shown} and {len(checked) - _WARNING_SAMPLE} more"
2541
+ self.warnings.append(
2542
+ f"{len(checked)} checked-out file(s) were copied from their last checked-in version "
2543
+ f"(in-progress edits are not visible over REST): {shown}"
2544
+ )
2545
+
2546
+ def _report_drafts(self, items: list[MigrationItem]) -> None:
2547
+ """Warn about files whose current version is an un-published (minor) draft.
2548
+
2549
+ REST returns the *draft* content, so the copy is faithful to the version the
2550
+ source reports — but version history is not preserved, so the published
2551
+ version a draft supersedes never reaches the target and the copy keeps the
2552
+ draft alone. Verification compares the same read and cannot see the
2553
+ difference, so the loss is reported here instead of passing silently.
2554
+
2555
+ The signal rides the file listing (``MinorVersion``), so this costs no extra
2556
+ request: a published file is ``x.0``, a draft ``x.n`` with ``n > 0``.
2557
+ """
2558
+ drafts: list[str] = []
2559
+ for item in items:
2560
+ if item.item_type == "folder":
2561
+ continue
2562
+ file = self._files.get(item.dest_path)
2563
+ if file is None or not file.minor_version:
2564
+ continue
2565
+ drafts.append(item.dest_path)
2566
+ if not drafts:
2567
+ return
2568
+ drafts.sort()
2569
+ shown = ", ".join(drafts[:_WARNING_SAMPLE])
2570
+ if len(drafts) > _WARNING_SAMPLE:
2571
+ shown = f"{shown} and {len(drafts) - _WARNING_SAMPLE} more"
2572
+ self.warnings.append(
2573
+ f"{len(drafts)} file(s) are on an un-published (minor) version: the draft content "
2574
+ f"is copied, the published version it supersedes is not (version history is not "
2575
+ f"preserved): {shown}"
2576
+ )
2577
+
2578
+ def read(self, item: MigrationItem) -> object:
264
2579
  if item.item_type == "folder":
265
- return b""
2580
+ # A folder's payload is its column values (empty when it carries none).
2581
+ return self._folder_values(item) or b""
266
2582
  file = self._files.get(item.dest_path)
267
2583
  if file is None:
268
2584
  raise FileNotFoundError(item.source_path)
@@ -276,10 +2592,237 @@ class SharePointLibrarySource:
276
2592
  file.download_session(buffer, chunk_downloaded=_chunk_downloaded).execute_query()
277
2593
  return buffer.getvalue()
278
2594
 
2595
+ def read_version_history(self, item: MigrationItem) -> tuple[str | None, list[tuple[str, bytes]]]:
2596
+ """Read the file's current version label and its older versions.
2597
+
2598
+ Returns ``(current_label, older)`` where ``older`` is oldest-first and
2599
+ excludes the current version (which :meth:`read` already supplies). The
2600
+ current label comes from ``UIVersionLabel``; older content is streamed
2601
+ from each ``File.Versions`` entry. Folders have no version history.
2602
+ """
2603
+ if item.item_type == "folder":
2604
+ return None, []
2605
+ file = self._files.get(item.dest_path)
2606
+ if file is None:
2607
+ raise FileNotFoundError(item.source_path)
2608
+ if file.ui_version_label is None:
2609
+ file.ensure_property("UIVersionLabel").execute_query()
2610
+ older: list[tuple[str, bytes]] = []
2611
+ for version in file.versions.get().execute_query():
2612
+ label = version.version_label
2613
+ if not label:
2614
+ continue
2615
+ data = version.open_binary_stream().execute_query().value
2616
+ older.append((label, data or b""))
2617
+ older.sort(key=lambda row: _version_sort_key(row[0]))
2618
+ return file.ui_version_label, older
2619
+
2620
+ @property
2621
+ def supports_folder_records(self) -> bool:
2622
+ """Whether a folder's column values are migrated *and* comparable."""
2623
+ return self._list_source is not None
2624
+
279
2625
  def checksum(self, item: MigrationItem) -> str:
280
2626
  if item.item_type == "folder":
281
- return hashlib.md5(b"").hexdigest()
282
- return hashlib.md5(self.read(item)).hexdigest()
2627
+ return _content_checksum(_canonicalize_taxonomy_record(self._folder_values(item)))
2628
+ return hashlib.md5(cast(bytes, self.read(item))).hexdigest()
2629
+
2630
+ def _folder_values(self, item: MigrationItem) -> dict:
2631
+ """The source folder's column values (empty when it carries none)."""
2632
+ if self._folder_payloads is None:
2633
+ payloads: dict[str, dict] = {}
2634
+ if self._sp_list is None or self._list_source is None:
2635
+ self.warnings.append(
2636
+ "folder column values were not read: the parent library is unknown "
2637
+ "(pass sp_list to SharePointLibrarySource)"
2638
+ )
2639
+ else:
2640
+ payloads.update(self._list_source.folder_records())
2641
+ self.warnings.extend(self._list_source.warnings)
2642
+ self._folder_payloads = payloads
2643
+ return self._folder_payloads.get(str(item.source_path).rstrip("/"), {})
2644
+
2645
+ def read_permissions(self, item: MigrationItem) -> list[PermissionEntry]:
2646
+ """Read the item's role assignments (for best-effort ACL preservation).
2647
+
2648
+ Returns one :class:`PermissionEntry` per principal (user or group), keyed
2649
+ by login name; empty for items with no unique assignments.
2650
+ """
2651
+ securable = self._securable(item)
2652
+ if securable is None:
2653
+ return []
2654
+ # Files: reuse the unique-ACL flag read with the authorship pass (the
2655
+ # ``File``/``ListItem`` resources do not expose it without an extra GET).
2656
+ if item.item_type != "folder" and self._item_unique is not None:
2657
+ unique = self._item_unique.get(item.source_path)
2658
+ if unique is not None:
2659
+ securable.properties["HasUniqueRoleAssignments"] = unique
2660
+ if not _has_unique_role_assignments(securable):
2661
+ return []
2662
+ return _read_role_assignments(securable, resolve=self._principal_for, normalize=self._normalize_name)
2663
+
2664
+ def _normalize_name(self, name: str) -> str:
2665
+ """Canonicalize a principal name (default groups -> ``default:<Kind>``)."""
2666
+ context = getattr(self._folder, "context", None)
2667
+ web = getattr(context, "web", None) if context is not None else None
2668
+ if web is None:
2669
+ return name
2670
+ if self._default_groups is None:
2671
+ self._default_groups = _DefaultGroups(web)
2672
+ return self._default_groups.normalize(name)
2673
+
2674
+ def read_metadata(self, item: MigrationItem) -> dict | None:
2675
+ """Comparable attributes of the source item (for the post-run metadata diff)."""
2676
+ if item.item_type == "folder":
2677
+ folder = self._folders.get(str(item.dest_path).rstrip("/"))
2678
+ if folder is None:
2679
+ return None
2680
+ return {
2681
+ "created": iso_or_none(folder.time_created),
2682
+ "modified": iso_or_none(folder.time_last_modified),
2683
+ }
2684
+ file = self._files.get(item.dest_path)
2685
+ if file is None:
2686
+ return None
2687
+ metadata = {
2688
+ "created": iso_or_none(file.time_created),
2689
+ "modified": iso_or_none(file.time_last_modified),
2690
+ "size_bytes": file.length or 0,
2691
+ }
2692
+ self._file_authors()
2693
+ state = (self._item_moderation or {}).get(item.source_path)
2694
+ if state:
2695
+ metadata["moderation_status"] = state.get("_ModerationStatus")
2696
+ return metadata
2697
+
2698
+ def read_authorship(self, item: MigrationItem) -> tuple[str | None, str | None]:
2699
+ """The source author/editor login names (for the authorship diff)."""
2700
+ return (
2701
+ item.author.login_name if item.author else None,
2702
+ item.editor.login_name if item.editor else None,
2703
+ )
2704
+
2705
+ def _securable(self, item: MigrationItem):
2706
+ if item.item_type == "folder":
2707
+ return self._folder.context.web.get_folder_by_server_relative_path(item.source_path).list_item_all_fields
2708
+ file = self._files.get(item.dest_path)
2709
+ return file.listItemAllFields if file is not None else None
2710
+
2711
+ def _principal_for(self, user_id: Any) -> "Principal | None":
2712
+ """Resolve a site-user id to a :class:`Principal` (login + PUID), cached."""
2713
+ key = parse_int(user_id)
2714
+ if key is None:
2715
+ return None
2716
+ if key in self._users:
2717
+ return self._users[key]
2718
+ principal: "Principal | None" = None
2719
+ try:
2720
+ user = self._folder.context.web.site_users.get_by_id(cast("str", key)).get().execute_query()
2721
+ user_id_info = user.properties.get("UserId")
2722
+ raw_id = getattr(user_id_info, "NameId", None)
2723
+ system_id = normalize_puid(raw_id)
2724
+ if raw_id and system_id is None:
2725
+ # e.g. the app principal, whose ``UserId.NameId`` is not a PUID.
2726
+ # Emitting it would fail the whole ingestion job, so drop it.
2727
+ self.warnings.append(
2728
+ f"user {key} ({user.login_name!r}) has no usable PUID ({raw_id!r}); "
2729
+ "it is omitted from the server-side user map"
2730
+ )
2731
+ principal = Principal(
2732
+ login_name=user.login_name or "",
2733
+ system_id=system_id,
2734
+ display_name=user.title,
2735
+ email=user.properties.get("Email"),
2736
+ )
2737
+ except Exception as e: # noqa: BLE001 — a missing user degrades to no authorship
2738
+ self.warnings.append(f"user {key} could not be resolved: {e}")
2739
+ self._users[key] = principal
2740
+ return principal
2741
+
2742
+ def _file_authors(self) -> dict[str, tuple[int | None, int | None]]:
2743
+ """Author/editor ids by server-relative file URL (one list-items read).
2744
+
2745
+ ``File.Author``/``ModifiedBy`` is a non-expandable navigation on the File
2746
+ resource, so the ids come from the parent library's list items.
2747
+ """
2748
+ if self._item_authors is not None:
2749
+ return self._item_authors
2750
+ authors: dict[str, tuple[int | None, int | None]] = {}
2751
+ unique: dict[str, bool] = {}
2752
+ moderation: dict[str, dict] = {}
2753
+ checkout: set[str] = set()
2754
+ moderates = self._moderation_enabled()
2755
+ if self._sp_list is not None:
2756
+ try:
2757
+ # ``CheckoutUser`` is a user field: it only projects when its
2758
+ # sub-properties are selected *and* the field is expanded — a bare
2759
+ # ``$select=CheckoutUser`` is rejected by the server.
2760
+ select = [
2761
+ "FileRef",
2762
+ "AuthorId",
2763
+ "EditorId",
2764
+ "HasUniqueRoleAssignments",
2765
+ "CheckoutUser/Id",
2766
+ "CheckoutUser/Title",
2767
+ ]
2768
+ if moderates:
2769
+ select.extend(_MODERATION_FIELDS)
2770
+ items = self._sp_list.items.select(select).expand(["CheckoutUser"]).get_all().execute_query()
2771
+ for item in items:
2772
+ ref = item.properties.get("FileRef")
2773
+ if ref:
2774
+ authors[ref] = (
2775
+ parse_int(item.properties.get("AuthorId")),
2776
+ parse_int(item.properties.get("EditorId")),
2777
+ )
2778
+ unique[ref] = bool(item.properties.get("HasUniqueRoleAssignments"))
2779
+ if item.properties.get("CheckoutUser"):
2780
+ checkout.add(ref)
2781
+ if moderates:
2782
+ state = _moderation_state(item.properties)
2783
+ if state:
2784
+ moderation[ref] = state
2785
+ except Exception as e: # noqa: BLE001 — authorship is best-effort
2786
+ self.warnings.append(f"author/editor read failed: {e}")
2787
+ self._item_authors = authors
2788
+ self._item_unique = unique
2789
+ self._item_moderation = moderation
2790
+ self._item_checkout = checkout
2791
+ return authors
2792
+
2793
+ def _moderation_enabled(self) -> bool:
2794
+ """Whether the parent library enables content approval (read once)."""
2795
+ if self._moderation_on is None:
2796
+ self._moderation_on = False
2797
+ if self._sp_list is not None:
2798
+ try:
2799
+ self._sp_list.ensure_properties(["EnableModeration"]).get().execute_query()
2800
+ self._moderation_on = bool(self._sp_list.properties.get("EnableModeration"))
2801
+ except Exception as e: # noqa: BLE001 — approval state is best-effort
2802
+ self.warnings.append(f"moderation setting read failed: {e}")
2803
+ return self._moderation_on
2804
+
2805
+ @property
2806
+ def supports_item_state(self) -> bool:
2807
+ """Whether approval state can be read (needs the parent library)."""
2808
+ return self._list_source is not None
2809
+
2810
+ def read_item_state(self, item: MigrationItem) -> dict | None:
2811
+ """Approval state that a fresh upload would not reproduce.
2812
+
2813
+ An uploaded document starts out *approved*, so only a draft/pending or
2814
+ rejected source file carries state, together with its approval comments.
2815
+ """
2816
+ if item.item_type == "folder" or self._list_source is None:
2817
+ return None
2818
+ self._file_authors()
2819
+ state = (self._item_moderation or {}).get(item.source_path)
2820
+ if not state:
2821
+ return None
2822
+ status = state.get("_ModerationStatus")
2823
+ if status is None or status == _APPROVED_STATUS:
2824
+ return None
2825
+ return state
283
2826
 
284
2827
  def close(self) -> None:
285
2828
  pass
@@ -290,29 +2833,177 @@ class SharePointLibraryTarget:
290
2833
 
291
2834
  Uses the simple upload for files up to ~4MB; ``write_many`` (parallel,
292
2835
  ``concurrency > 1``) uses ``create_upload_session`` for larger files.
2836
+
2837
+ Pass ``sp_list`` (the target library) to also replay a folder's column values: a
2838
+ folder is a list item, so a document set's metadata or a managed folder's
2839
+ department is written onto the created folder's item. ``content_type_map``
2840
+ rewrites the folder's content type id to its target counterpart, exactly as it
2841
+ does for an item record.
293
2842
  """
294
2843
 
295
- def __init__(self, library_folder: "Folder", concurrency: int = 1) -> None:
2844
+ #: Files carry content-approval state (``apply_item_state``). Documents refuse a
2845
+ #: moderation change combined with other property writes, so it is a write of its
2846
+ #: own, applied after the timestamps that would otherwise re-approve the file.
2847
+ supports_item_state = True
2848
+
2849
+ def rebind(self) -> "SharePointLibraryTarget":
2850
+ """This target on its own cloned context (see :meth:`SharePointListSource.rebind`)."""
2851
+ context = _cloned_context(self._folder)
2852
+ sp_list = _cloned_list(self._sp_list, context) if self._sp_list is not None else None
2853
+ return SharePointLibraryTarget(
2854
+ _cloned_folder(self._folder, context),
2855
+ concurrency=self._concurrency,
2856
+ sp_list=sp_list,
2857
+ content_type_map=self._content_type_map,
2858
+ )
2859
+
2860
+ def __init__(
2861
+ self,
2862
+ library_folder: "Folder",
2863
+ concurrency: int = 1,
2864
+ sp_list: "SPList | None" = None,
2865
+ content_type_map: "ContentTypeMap | None" = None,
2866
+ ) -> None:
296
2867
  self._folder = library_folder
297
2868
  self._concurrency = concurrency
2869
+ # The folder-record mapping is the record mapping: reuse the list target so a
2870
+ # folder's Lookup/Person/taxonomy/choice values resolve the same way.
2871
+ self._sp_list = sp_list
2872
+ self._list_target = (
2873
+ SharePointListTarget(sp_list, content_type_map=content_type_map) if sp_list is not None else None
2874
+ )
2875
+ self._content_type_map = content_type_map
2876
+ self.warnings: list[str] = []
2877
+ self._login_cache: dict[int, str | None] = {}
2878
+ self._principals_cache: _TargetPrincipals | None = None
2879
+ # Author/Editor values written by ``apply_authorship`` and folded into the
2880
+ # final timestamp write so ``Editor`` isn't reset by the latter.
2881
+ self._pending_authorship: dict[str, dict] = {}
2882
+ # Target web time zone (lazily loaded) and a UTC->local conversion cache.
2883
+ self._time_zone = None
2884
+ self._local_cache: dict[str, str] = {}
2885
+ self._field_scan: SharePointListSource | None = None
2886
+
2887
+ def _utc_to_local(self, *values: str | None) -> list[str | None]:
2888
+ """Convert UTC timestamp strings to web-local wall-clock (one round trip).
2889
+
2890
+ Document items parse form dates in the web's locale, so the desired UTC
2891
+ instant must be converted to local wall-clock first. The conversion runs
2892
+ server-side (``TimeZone.UTCToLocalTime``) so DST is handled correctly.
2893
+ Results are cached by the exact UTC value.
2894
+ """
2895
+ if self._time_zone is None:
2896
+ self._time_zone = self._folder.context.web.regional_settings.time_zone
2897
+ outputs: list[str | None] = [None] * len(values)
2898
+ pending: dict[str, object] = {}
2899
+ assignments: list[tuple[int, str]] = []
2900
+ for index, value in enumerate(values):
2901
+ if not value:
2902
+ continue
2903
+ utc = _sp_utc_timestamp(value)
2904
+ if utc is None:
2905
+ continue
2906
+ if not utc.endswith("Z"):
2907
+ # Unparseable value: pass it through unchanged so a rejection is
2908
+ # surfaced by ``_report_rejected_fields`` rather than silently lost.
2909
+ outputs[index] = str(value)
2910
+ continue
2911
+ cached = self._local_cache.get(utc)
2912
+ if cached is not None:
2913
+ outputs[index] = cached
2914
+ continue
2915
+ instant = parse_datetime(utc)
2916
+ if instant is None:
2917
+ outputs[index] = str(value)
2918
+ continue
2919
+ if utc not in pending:
2920
+ pending[utc] = self._time_zone.utc_to_local_time(instant)
2921
+ assignments.append((index, utc))
2922
+ if pending:
2923
+ self._folder.context.execute_query()
2924
+ for utc, result in pending.items():
2925
+ local = _sp_local_timestamp(getattr(result, "value", None))
2926
+ if local is not None:
2927
+ self._local_cache[utc] = local
2928
+ for index, utc in assignments:
2929
+ outputs[index] = self._local_cache.get(utc)
2930
+ return outputs
2931
+
2932
+ def _principals(self) -> _TargetPrincipals:
2933
+ """The (lazily built) target principal/role resolver."""
2934
+ if self._principals_cache is None:
2935
+ self._principals_cache = _TargetPrincipals(self._folder.context.web, self.warnings)
2936
+ return self._principals_cache
298
2937
 
299
2938
  def label(self) -> str:
300
2939
  return f"library:{self._folder.server_relative_url}"
301
2940
 
302
2941
  def _url(self, item: MigrationItem) -> str:
303
- return f"{(self._folder.server_relative_url or '').rstrip('/')}/{item.dest_path}"
2942
+ return f"{(self._folder.server_relative_url or '').rstrip('/')}/{str(item.dest_path).strip('/')}"
304
2943
 
305
2944
  def exists(self, item: MigrationItem) -> bool:
2945
+ url = self._url(item)
306
2946
  try:
307
- self._folder.context.web.get_file_by_server_relative_url(self._url(item)).get().execute_query()
2947
+ if item.item_type == "folder":
2948
+ self._folder.context.web.get_folder_by_server_relative_url(url).get().execute_query()
2949
+ else:
2950
+ self._folder.context.web.get_file_by_server_relative_url(url).get().execute_query()
308
2951
  return True
309
- except Exception: # noqa: BLE001 — a missing file surfaces as a request error
2952
+ except Exception: # noqa: BLE001 — a missing item surfaces as a request error
310
2953
  return False
311
2954
 
2955
+ def _ensure_folders(self, items: list[MigrationItem]) -> None:
2956
+ """Create folder items (deduplicated to deepest paths) in one round-trip."""
2957
+ paths = [str(item.dest_path).strip("/") for item in items]
2958
+ paths = [path for path in paths if path]
2959
+ if not paths:
2960
+ return
2961
+ self._folder.ensure_folders(paths)
2962
+ self._folder.context.execute_query()
2963
+
312
2964
  def write(self, item: MigrationItem, payload: object) -> None:
2965
+ if item.item_type == "folder":
2966
+ self._ensure_folders([item])
2967
+ if isinstance(payload, dict):
2968
+ self._apply_folder_values(item, payload)
2969
+ return
313
2970
  content = payload if isinstance(payload, bytes) else str(payload).encode("utf-8")
314
2971
  self._folder.upload_file(item.dest_path, content).execute_query()
315
2972
 
2973
+ @property
2974
+ def supports_folder_records(self) -> bool:
2975
+ """Whether a folder's column values are migrated *and* comparable."""
2976
+ return self._list_target is not None
2977
+
2978
+ def _apply_folder_values(self, item: MigrationItem, record: dict) -> None:
2979
+ """Write a folder's column values onto the folder's underlying list item."""
2980
+ assert self._list_target is not None
2981
+ values = _folder_record_values(record)
2982
+ if not values:
2983
+ return
2984
+ values = self._list_target.translate_record(values)
2985
+ folder_item = self._securable(item)
2986
+ for key, value in values.items():
2987
+ folder_item.set_property(key, value)
2988
+ try:
2989
+ folder_item.update().execute_query()
2990
+ except Exception as e: # noqa: BLE001 — a folder's structure is worth more than its values
2991
+ self.warnings.append(f"folder column values for {item.dest_path!r} could not be written: {e}")
2992
+
2993
+ def _folder_projection(self) -> list[str]:
2994
+ """The target's folder columns (read once) — the set the source projected."""
2995
+ if self._sp_list is None:
2996
+ return []
2997
+ if self._field_scan is None:
2998
+ # Field definitions are read by the same code on both sides: structure
2999
+ # provisioning keeps the internal names, so the projections line up.
3000
+ self._field_scan = SharePointListSource(self._sp_list)
3001
+ try:
3002
+ return self._field_scan.folder_projection()
3003
+ except Exception as e: # noqa: BLE001 — without a projection no folder values move
3004
+ self.warnings.append(f"could not read the target columns for folder values: {e}")
3005
+ return []
3006
+
316
3007
  def write_many(
317
3008
  self,
318
3009
  items: list[MigrationItem],
@@ -326,29 +3017,273 @@ class SharePointLibraryTarget:
326
3017
  """
327
3018
  from office365.migration.sharepoint.transfer import _transfer_files_parallel
328
3019
 
3020
+ failures: list[Failure] = []
3021
+ folders = [item for item in items if item.item_type == "folder"]
3022
+ if folders:
3023
+ try:
3024
+ self._ensure_folders(folders)
3025
+ except Exception: # noqa: BLE001 — fall back to per-folder to attribute errors
3026
+ for folder in folders:
3027
+ try:
3028
+ self._ensure_folders([folder])
3029
+ except Exception as e: # noqa: BLE001
3030
+ failures.append((folder.dest_path, str(e)))
3031
+ # A folder's column values can only be written once its item exists, so they
3032
+ # follow the (batched) folder creation.
3033
+ for item, payload in zip(items, payloads):
3034
+ if item.item_type == "folder" and isinstance(payload, dict):
3035
+ self._apply_folder_values(item, payload)
329
3036
  files = [
330
3037
  (item.dest_path, payload if isinstance(payload, bytes) else str(payload).encode("utf-8"))
331
3038
  for item, payload in zip(items, payloads)
3039
+ if item.item_type != "folder"
332
3040
  ]
333
- return _transfer_files_parallel(
334
- self._folder,
335
- files,
336
- concurrency=concurrency or self._concurrency or 1,
337
- )
3041
+ if files:
3042
+ failures.extend(
3043
+ _transfer_files_parallel(
3044
+ self._folder,
3045
+ files,
3046
+ concurrency=concurrency or self._concurrency or 1,
3047
+ )
3048
+ )
3049
+ return failures
338
3050
 
339
3051
  def list_paths(self) -> list[str]:
340
3052
  root = (self._folder.server_relative_url or "").rstrip("/")
341
- loaded = self._folder.get_files(recursive=True).execute_query()
342
- return [(f.server_relative_url or "")[len(root) :].lstrip("/") for f in loaded]
3053
+ extra = _site_assets_scaffolding(self._folder)
3054
+ loaded_files = self._folder.get_files(recursive=True).execute_query()
3055
+ loaded_folders = self._folder.get_folders(recursive=True).execute_query()
3056
+ paths = [(f.server_relative_url or "")[len(root) :].lstrip("/") for f in loaded_files]
3057
+ paths += [f"{(f.server_relative_url or '')[len(root) :].lstrip('/')}/" for f in loaded_folders]
3058
+ # Mirror the source projection: SharePoint-owned scaffolding (``Forms/``,
3059
+ # ``desktop.ini``, and on SiteAssets the site icon + auto-provisioned
3060
+ # notebook) is recreated server-side, never migrated, so it must not be
3061
+ # reported as target-only content during verification. Source folder paths
3062
+ # carry a trailing slash; target folder paths mirror that.
3063
+ return [p for p in paths if p != "/" and not _is_system_path(p, extra)]
343
3064
 
344
- def checksum(self, item: MigrationItem) -> str:
3065
+ def read(self, item: MigrationItem) -> bytes:
3066
+ """Download the written item's bytes (used by verification for Office files)."""
3067
+ if item.item_type == "folder":
3068
+ return b""
345
3069
  file = self._folder.context.web.get_file_by_server_relative_url(self._url(item)).get().execute_query()
346
3070
  buffer = io.BytesIO()
347
3071
  file.download(buffer).execute_query()
348
- return hashlib.md5(buffer.getvalue()).hexdigest()
3072
+ return buffer.getvalue()
3073
+
3074
+ def checksum(self, item: MigrationItem) -> str:
3075
+ if item.item_type == "folder":
3076
+ values = self._target_folder_values(item)
3077
+ if values is None or self._list_target is None:
3078
+ return ""
3079
+ return self._list_target.content_checksum(values)
3080
+ return hashlib.md5(self.read(item)).hexdigest()
3081
+
3082
+ def _target_folder_values(self, item: MigrationItem) -> dict | None:
3083
+ """The target folder's column values as they read back (``None`` if unknown)."""
3084
+ columns = self._folder_projection()
3085
+ if not columns:
3086
+ return None
3087
+ list_item = self._securable(item).select(columns).get().execute_query()
3088
+ return _folder_record_values(dict(list_item.properties))
3089
+
3090
+ def modified(self, item: MigrationItem) -> str:
3091
+ """Last-modified of the target file (for incremental migration)."""
3092
+ if item.item_type == "folder":
3093
+ return ""
3094
+ file = self._folder.context.web.get_file_by_server_relative_url(self._url(item)).get().execute_query()
3095
+ return iso_or_none(file.time_last_modified) or ""
3096
+
3097
+ def apply_timestamps(self, item: MigrationItem) -> None:
3098
+ """Best-effort: restore ``Created``/``Modified`` on the written item.
3099
+
3100
+ Uses ``ValidateUpdateListItem``, the only REST path that can set these
3101
+ system fields. For files it runs as a system update
3102
+ (``bNewDocumentUpdate=True``, the CSOM ``UpdateOverwriteVersion`` path) so
3103
+ the metadata lands without creating a new version; folders have no version
3104
+ history. ``preserve_versions`` still needs the server-side API. Authorship
3105
+ values resolved for the same item ride along in this write.
3106
+ """
3107
+ form_values: dict = {}
3108
+ created, modified = self._utc_to_local(item.created, item.modified)
3109
+ if created:
3110
+ form_values["Created"] = created
3111
+ if modified:
3112
+ form_values["Modified"] = modified
3113
+ form_values.update(self._pending_authorship.pop(item.dest_path, {}))
3114
+ if not form_values:
3115
+ return
3116
+ securable = self._securable(item)
3117
+ if securable is None:
3118
+ return
3119
+ result = securable.validate_update_list_item(
3120
+ form_values,
3121
+ dates_in_utc=True,
3122
+ new_document_update=item.item_type != "folder",
3123
+ ).execute_query()
3124
+ _report_rejected_fields(result, self.warnings, f"timestamps {item.dest_path}")
3125
+
3126
+ def apply_authorship(self, item: MigrationItem) -> None:
3127
+ """Best-effort: resolve ``Author``/``Editor`` and cache them for one write.
3128
+
3129
+ A principal is applied only when its login name resolves to a target user
3130
+ (``EnsureUser``); unresolved principals are skipped (same-tenant only).
3131
+
3132
+ Nothing is sent here: a separate write per item doubled the cost of a
3133
+ preserved run, and a system update re-approves a document, so the cached
3134
+ values are better folded into the timestamps write (or in
3135
+ :meth:`finalize_fidelity` when timestamps are not preserved).
3136
+ """
3137
+ securable = self._securable(item)
3138
+ if securable is None:
3139
+ return
3140
+ author = self._principals().user(item.author.login_name if item.author else None)
3141
+ editor = self._principals().user(item.editor.login_name if item.editor else None)
3142
+ if author is not None and _is_system_principal(author):
3143
+ author = None
3144
+ if editor is not None and _is_system_principal(editor):
3145
+ editor = None
3146
+ if author is None and editor is None:
3147
+ return
3148
+ form_values: dict[str, FieldUserValue] = {}
3149
+ if author is not None:
3150
+ form_values["Author"] = FieldUserValue(author.id, author.login_name)
3151
+ if editor is not None:
3152
+ form_values["Editor"] = FieldUserValue(editor.id, editor.login_name)
3153
+ self._pending_authorship[item.dest_path] = dict(form_values)
3154
+
3155
+ def finalize_fidelity(self, item: MigrationItem) -> None:
3156
+ """Write the fidelity values that were only cached for this item.
3157
+
3158
+ The last hook wins the write: with timestamps preserved that is
3159
+ :meth:`apply_timestamps`; without them it is this method, so an item costs
3160
+ one system update instead of one per property group. Runs before the
3161
+ approval write, which must stay last.
3162
+ """
3163
+ form_values = self._pending_authorship.pop(item.dest_path, {})
3164
+ if not form_values:
3165
+ return
3166
+ securable = self._securable(item)
3167
+ if securable is None:
3168
+ return
3169
+ result = securable.validate_update_list_item(
3170
+ form_values,
3171
+ dates_in_utc=True,
3172
+ new_document_update=item.item_type != "folder",
3173
+ ).execute_query()
3174
+ _report_rejected_fields(result, self.warnings, f"authorship {item.dest_path}")
3175
+
3176
+ def apply_permissions(self, item: MigrationItem, permissions: list[PermissionEntry]) -> None:
3177
+ """Best-effort: replay a file's or folder's unique ACLs onto the target item.
3178
+
3179
+ Same-tenant only — cross-tenant identity mapping is out of scope. See
3180
+ :func:`_replay_role_assignments` for what happens to principals, roles and
3181
+ inheritance that cannot be resolved.
3182
+ """
3183
+ securable = self._securable(item)
3184
+ if securable is None:
3185
+ return
3186
+ _replay_role_assignments(securable, self._principals(), permissions, self.warnings, item.dest_path)
3187
+ securable.context.execute_query()
3188
+
3189
+ def apply_item_state(self, item: MigrationItem, state: dict) -> None:
3190
+ """Best-effort: restore a migrated file's content-approval state.
3191
+
3192
+ An uploaded file starts out approved, and the timestamp/authorship system
3193
+ updates approve it again, so a source draft or rejected file would
3194
+ otherwise silently become visible. Documents reject a moderation change
3195
+ combined with other properties (``You cannot change moderation status and
3196
+ set other item properties at that same time.``), hence a separate write,
3197
+ applied last. A library without moderation enabled has no such fields: the
3198
+ write fails and is reported, never fatal.
3199
+ """
3200
+ if item.item_type == "folder" or not state:
3201
+ return
3202
+ securable = self._securable(item)
3203
+ if securable is None:
3204
+ return
3205
+ try:
3206
+ result = securable.validate_update_list_item(
3207
+ dict(state),
3208
+ dates_in_utc=True,
3209
+ new_document_update=True,
3210
+ ).execute_query()
3211
+ except Exception as e: # noqa: BLE001 — approval state is best-effort
3212
+ self.warnings.append(f"approval state for {item.dest_path!r} could not be restored: {e}")
3213
+ return
3214
+ _report_rejected_fields(result, self.warnings, f"approval state {item.dest_path}")
3215
+
3216
+ def read_metadata(self, item: MigrationItem) -> dict | None:
3217
+ """Comparable attributes of the written item (for the metadata diff)."""
3218
+ if item.item_type == "folder":
3219
+ # A folder is an item too: the timestamp system update lands on its list
3220
+ # item, and the folder resource reflects it (same read as for a file).
3221
+ folder = (
3222
+ self._folder.context.web.get_folder_by_server_relative_path(self._url(item).rstrip("/"))
3223
+ .get()
3224
+ .execute_query()
3225
+ )
3226
+ return {
3227
+ "created": iso_or_none(folder.time_created),
3228
+ "modified": iso_or_none(folder.time_last_modified),
3229
+ }
3230
+ file = self._folder.context.web.get_file_by_server_relative_url(self._url(item)).get().execute_query()
3231
+ metadata = {
3232
+ "created": iso_or_none(file.time_created),
3233
+ "modified": iso_or_none(file.time_last_modified),
3234
+ "size_bytes": file.length or 0,
3235
+ }
3236
+ status = self._target_moderation_status(item)
3237
+ if status is not None:
3238
+ metadata["moderation_status"] = status
3239
+ return metadata
3240
+
3241
+ def _target_moderation_status(self, item: MigrationItem) -> str | None:
3242
+ """The written file's approval status, or ``None`` when not readable."""
3243
+ securable = self._securable(item)
3244
+ if securable is None:
3245
+ return None
3246
+ try:
3247
+ securable.select(["OData__ModerationStatus"]).get().execute_query()
3248
+ except Exception: # noqa: BLE001 — a library without moderation has no such column
3249
+ return None
3250
+ status = securable.properties.get("OData__ModerationStatus")
3251
+ return None if status is None else str(status)
3252
+
3253
+ def read_permissions(self, item: MigrationItem) -> list[PermissionEntry]:
3254
+ """Read the written item's *unique* role assignments (for the permission diff)."""
3255
+ securable = self._securable(item)
3256
+ if securable is None or not _has_unique_role_assignments(securable, refresh=True):
3257
+ return []
3258
+ return _read_role_assignments(securable, normalize=self._principals().normalize)
3259
+
3260
+ def _fresh_securable(self, item: MigrationItem):
3261
+ """Re-read the written item so its properties reflect what was applied."""
3262
+ securable = self._securable(item)
3263
+ if securable is not None:
3264
+ securable.get().execute_query()
3265
+ return securable
3266
+
3267
+ def read_authorship(self, item: MigrationItem) -> tuple[str | None, str | None]:
3268
+ """The written item's author/editor login names (for the authorship diff)."""
3269
+ securable = self._fresh_securable(item)
3270
+ if securable is None:
3271
+ return (None, None)
3272
+ properties = securable.properties
3273
+ return (
3274
+ _user_login(self._folder.context.web, properties.get("AuthorId"), self._login_cache),
3275
+ _user_login(self._folder.context.web, properties.get("EditorId"), self._login_cache),
3276
+ )
3277
+
3278
+ def _securable(self, item: MigrationItem):
3279
+ url = self._url(item).rstrip("/")
3280
+ if item.item_type == "folder":
3281
+ return self._folder.context.web.get_folder_by_server_relative_path(url).list_item_all_fields
3282
+ return self._folder.context.web.get_file_by_server_relative_url(url).listItemAllFields
349
3283
 
350
3284
  def commit(self, options=None) -> None:
351
- pass
3285
+ self._pending_authorship.clear()
3286
+ self._local_cache.clear()
352
3287
 
353
3288
  def close(self) -> None:
354
3289
  pass