dipex 5.5.2__tar.gz → 5.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. {dipex-5.5.2 → dipex-5.7.0}/PKG-INFO +1 -1
  2. dipex-5.7.0/integrations/SD_Lon/alembic/env.py +68 -0
  3. dipex-5.7.0/integrations/SD_Lon/alembic/versions/26d00ae9c67f_add_payload_table.py +47 -0
  4. dipex-5.7.0/integrations/SD_Lon/payload_db/__init__.py +40 -0
  5. dipex-5.7.0/integrations/SD_Lon/payload_db/engine.py +14 -0
  6. dipex-5.7.0/integrations/SD_Lon/payload_db/models.py +23 -0
  7. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/fix_departments.py +30 -5
  8. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/sd_changed_at.py +34 -4
  9. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/sd_changed_at_redo.py +8 -1
  10. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/sd_common.py +20 -4
  11. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/sd_fixup.py +13 -2
  12. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/sd_importer.py +33 -5
  13. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/sync_job_id.py +9 -1
  14. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/test_mo_against_sd.py +12 -1
  15. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/test_sd_connectivity.py +8 -0
  16. dipex-5.7.0/integrations/SD_Lon/tests/payload_db/test_engine.py +34 -0
  17. dipex-5.7.0/integrations/SD_Lon/tests/payload_db/test_log_payload.py +33 -0
  18. dipex-5.7.0/integrations/SD_Lon/tests/test_sd_common.py +75 -0
  19. dipex-5.7.0/integrations/calculate_primary/tests/__init__.py +0 -0
  20. {dipex-5.5.2 → dipex-5.7.0}/pyproject.toml +1 -1
  21. dipex-5.5.2/integrations/SD_Lon/tests/test_sd_common.py +0 -23
  22. {dipex-5.5.2 → dipex-5.7.0}/exporters/sql_export/__init__.py +0 -0
  23. {dipex-5.5.2 → dipex-5.7.0}/exporters/sql_export/gql_lora_cache_async.py +0 -0
  24. {dipex-5.5.2 → dipex-5.7.0}/exporters/sql_export/lc_for_jobs_db.py +0 -0
  25. {dipex-5.5.2 → dipex-5.7.0}/exporters/sql_export/log.py +0 -0
  26. {dipex-5.5.2 → dipex-5.7.0}/exporters/sql_export/lora_cache.py +0 -0
  27. {dipex-5.5.2 → dipex-5.7.0}/exporters/sql_export/main.py +0 -0
  28. {dipex-5.5.2 → dipex-5.7.0}/exporters/sql_export/old_lora_cache.py +0 -0
  29. {dipex-5.5.2 → dipex-5.7.0}/exporters/sql_export/sql_export.py +0 -0
  30. {dipex-5.5.2 → dipex-5.7.0}/exporters/sql_export/sql_table_defs.py +0 -0
  31. {dipex-5.5.2 → dipex-5.7.0}/exporters/sql_export/sql_url.py +0 -0
  32. {dipex-5.5.2 → dipex-5.7.0}/exporters/sql_export/trigger.py +0 -0
  33. {dipex-5.5.2 → dipex-5.7.0}/exporters/utils/priority_by_class.py +0 -0
  34. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/__init__.py +0 -0
  35. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/config.py +0 -0
  36. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/date_utils.py +0 -0
  37. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/employees.py +0 -0
  38. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/engagement.py +0 -0
  39. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/exceptions.py +0 -0
  40. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/graphql.py +0 -0
  41. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/it_systems.py +0 -0
  42. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/log.py +0 -0
  43. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/main.py +0 -0
  44. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/models.py +0 -0
  45. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/scripts/__init__.py +0 -0
  46. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/scripts/fix_monthly_hourly_divide.py +0 -0
  47. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/scripts/fix_status8.py +0 -0
  48. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/scripts/generate_org_unit_level_uuid.py +0 -0
  49. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/sd_cli.py +0 -0
  50. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/sd_log_analyzer.py +0 -0
  51. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/sd_payloads.py +0 -0
  52. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/sd_to_pydantic.py +0 -0
  53. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdlon/skip.py +0 -0
  54. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdtool/__init__.py +0 -0
  55. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdtool/config.py +0 -0
  56. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/sdtool/main.py +0 -0
  57. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/__init__.py +0 -0
  58. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/fixtures.py +0 -0
  59. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/org_manipulations.py +0 -0
  60. {dipex-5.5.2/integrations/SD_Lon/tests/sdtool → dipex-5.7.0/integrations/SD_Lon/tests/payload_db}/__init__.py +0 -0
  61. {dipex-5.5.2/integrations → dipex-5.7.0/integrations/SD_Lon/tests/sdtool}/__init__.py +0 -0
  62. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/sdtool/test_app.py +0 -0
  63. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/sdtool/test_config.py +0 -0
  64. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/sdtool/utils.py +0 -0
  65. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/test_config.py +0 -0
  66. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/test_date_utils.py +0 -0
  67. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/test_employee.py +0 -0
  68. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/test_engagement.py +0 -0
  69. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/test_fix_departments.py +0 -0
  70. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/test_graphql.py +0 -0
  71. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/test_it_systems.py +0 -0
  72. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/test_log.py +0 -0
  73. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/test_main.py +0 -0
  74. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/test_sd_changed_at.py +0 -0
  75. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/test_sd_importer.py +0 -0
  76. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/test_sd_log_analyzer.py +0 -0
  77. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/test_sd_to_pydantic.py +0 -0
  78. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/test_skip.py +0 -0
  79. {dipex-5.5.2 → dipex-5.7.0}/integrations/SD_Lon/tests/test_sync_job_id.py +0 -0
  80. {dipex-5.5.2/integrations/aarhus/tests → dipex-5.7.0/integrations}/__init__.py +0 -0
  81. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/config.py +0 -0
  82. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/dar_helper.py +0 -0
  83. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/initial.py +0 -0
  84. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/initial_classes.py +0 -0
  85. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/los_files.py +0 -0
  86. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/los_import.py +0 -0
  87. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/los_leder.py +0 -0
  88. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/los_org.py +0 -0
  89. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/los_pers.py +0 -0
  90. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/los_stam.py +0 -0
  91. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/payloads.py +0 -0
  92. {dipex-5.5.2/integrations/ad_integration → dipex-5.7.0/integrations/aarhus/tests}/__init__.py +0 -0
  93. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/tests/conftest.py +0 -0
  94. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/tests/helpers.py +0 -0
  95. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/tests/strategies.py +0 -0
  96. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/tests/test_config.py +0 -0
  97. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/tests/test_initial.py +0 -0
  98. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/tests/test_los_files.py +0 -0
  99. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/tests/test_los_import.py +0 -0
  100. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/tests/test_los_leder.py +0 -0
  101. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/tests/test_los_org.py +0 -0
  102. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/tests/test_los_pers.py +0 -0
  103. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/tests/test_los_stam.py +0 -0
  104. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/tests/test_payloads.py +0 -0
  105. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/tests/test_util.py +0 -0
  106. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/util.py +0 -0
  107. {dipex-5.5.2 → dipex-5.7.0}/integrations/aarhus/uuids.py +0 -0
  108. {dipex-5.5.2/integrations/ad_integration/tests → dipex-5.7.0/integrations/ad_integration}/__init__.py +0 -0
  109. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/ad_common.py +0 -0
  110. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/ad_exceptions.py +0 -0
  111. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/ad_fix_enddate.py +0 -0
  112. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/ad_jinja_filters.py +0 -0
  113. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/ad_life_cycle.py +0 -0
  114. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/ad_logger.py +0 -0
  115. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/ad_reader.py +0 -0
  116. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/ad_sync.py +0 -0
  117. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/ad_template_engine.py +0 -0
  118. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/ad_templates.py +0 -0
  119. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/ad_writer.py +0 -0
  120. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/import_ad_group_into_mo.py +0 -0
  121. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/mo_to_ad_sync.py +0 -0
  122. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/payloads.py +0 -0
  123. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/read_ad_conf_settings.py +0 -0
  124. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/sync_mo_uuid_to_ad.py +0 -0
  125. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/test_connectivity.py +0 -0
  126. {dipex-5.5.2/integrations/calculate_primary → dipex-5.7.0/integrations/ad_integration/tests}/__init__.py +0 -0
  127. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/mocks.py +0 -0
  128. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/name_simulator.py +0 -0
  129. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_ad_common.py +0 -0
  130. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_ad_fix_enddate.py +0 -0
  131. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_ad_jinja_filters.py +0 -0
  132. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_ad_life_cycle.py +0 -0
  133. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_ad_logger.py +0 -0
  134. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_ad_reader.py +0 -0
  135. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_ad_sync.py +0 -0
  136. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_ad_writer.py +0 -0
  137. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_dot_mapping.py +0 -0
  138. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_first_included.py +0 -0
  139. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_import_ad_group_into_mo.py +0 -0
  140. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_location_element.py +0 -0
  141. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_mo_data_source.py +0 -0
  142. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_mo_to_ad_sync.py +0 -0
  143. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_morestsource.py +0 -0
  144. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_read_ad_conf_settings.py +0 -0
  145. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_recursive_dict_update.py +0 -0
  146. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_sync_mo_uuid_to_ad.py +0 -0
  147. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_usernames.py +0 -0
  148. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/tests/test_utils.py +0 -0
  149. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/user_names.py +0 -0
  150. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/username_rules/method_2.py +0 -0
  151. {dipex-5.5.2 → dipex-5.7.0}/integrations/ad_integration/utils.py +0 -0
  152. {dipex-5.5.2/integrations/calculate_primary/tests → dipex-5.7.0/integrations/calculate_primary}/__init__.py +0 -0
  153. {dipex-5.5.2 → dipex-5.7.0}/integrations/calculate_primary/calculate_primary.py +0 -0
  154. {dipex-5.5.2 → dipex-5.7.0}/integrations/calculate_primary/common.py +0 -0
  155. {dipex-5.5.2 → dipex-5.7.0}/integrations/calculate_primary/default.py +0 -0
  156. {dipex-5.5.2 → dipex-5.7.0}/integrations/calculate_primary/opus.py +0 -0
  157. {dipex-5.5.2 → dipex-5.7.0}/integrations/calculate_primary/sd.py +0 -0
  158. {dipex-5.5.2 → dipex-5.7.0}/integrations/calculate_primary/tests/test_primary.py +0 -0
  159. {dipex-5.5.2 → dipex-5.7.0}/integrations/cpr_mapper.py +0 -0
  160. {dipex-5.5.2 → dipex-5.7.0}/integrations/dawa_helper.py +0 -0
  161. {dipex-5.5.2 → dipex-5.7.0}/integrations/kle/__init__.py +0 -0
  162. {dipex-5.5.2 → dipex-5.7.0}/integrations/kle/kle_import.py +0 -0
  163. {dipex-5.5.2 → dipex-5.7.0}/integrations/kle/kle_import_export.py +0 -0
  164. {dipex-5.5.2 → dipex-5.7.0}/integrations/kle/kle_xlsx.py +0 -0
  165. {dipex-5.5.2 → dipex-5.7.0}/integrations/kle/payloads.py +0 -0
  166. {dipex-5.5.2 → dipex-5.7.0}/integrations/opus/clear_and_import_opus.py +0 -0
  167. {dipex-5.5.2 → dipex-5.7.0}/integrations/opus/opus_diff_import.py +0 -0
  168. {dipex-5.5.2 → dipex-5.7.0}/integrations/opus/opus_exceptions.py +0 -0
  169. {dipex-5.5.2 → dipex-5.7.0}/integrations/opus/opus_file_reader.py +0 -0
  170. {dipex-5.5.2 → dipex-5.7.0}/integrations/opus/opus_helpers.py +0 -0
  171. {dipex-5.5.2 → dipex-5.7.0}/integrations/opus/opus_reimport_one.py +0 -0
  172. {dipex-5.5.2 → dipex-5.7.0}/integrations/opus/org_tree_print/main.py +0 -0
  173. {dipex-5.5.2 → dipex-5.7.0}/integrations/opus/payloads.py +0 -0
  174. {dipex-5.5.2 → dipex-5.7.0}/integrations/opus/tests/test_opus_diff_import.py +0 -0
  175. {dipex-5.5.2 → dipex-5.7.0}/integrations/opus/tests/test_opus_file_reader.py +0 -0
  176. {dipex-5.5.2 → dipex-5.7.0}/integrations/opus/tests/test_opus_helpers.py +0 -0
  177. {dipex-5.5.2 → dipex-5.7.0}/integrations/rundb/db_overview.py +0 -0
  178. {dipex-5.5.2 → dipex-5.7.0}/integrations/rundb/tests/test_db_overview.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: DIPEX
3
- Version: 5.5.2
3
+ Version: 5.7.0
4
4
  Summary: OS2mo-data-import-and-export
5
5
  Home-page: https://magenta.dk/
6
6
  License: MPL-2.0
@@ -0,0 +1,68 @@
1
+ # SPDX-FileCopyrightText: Magenta ApS <https://magenta.dk>
2
+ # SPDX-License-Identifier: MPL-2.0
3
+ # Initial version generated using `poetry run alembic init alembic`
4
+ from logging.config import fileConfig
5
+
6
+ from alembic import context
7
+ from payload_db.engine import get_db_url
8
+ from payload_db.engine import get_engine
9
+ from payload_db.models import Base
10
+
11
+
12
+ # this is the Alembic Config object, which provides
13
+ # access to the values within the .ini file in use.
14
+ config = context.config
15
+
16
+ # Interpret the config file for Python logging.
17
+ # This line sets up loggers basically.
18
+ if config.config_file_name is not None:
19
+ fileConfig(config.config_file_name)
20
+
21
+ # add your model's MetaData object here
22
+ # for 'autogenerate' support
23
+ # from myapp import mymodel
24
+ # target_metadata = mymodel.Base.metadata
25
+ target_metadata = Base.metadata
26
+
27
+
28
+ def run_migrations_offline() -> None:
29
+ """Run migrations in 'offline' mode.
30
+
31
+ This configures the context with just a URL
32
+ and not an Engine, though an Engine is acceptable
33
+ here as well. By skipping the Engine creation
34
+ we don't even need a DBAPI to be available.
35
+
36
+ Calls to context.execute() here emit the given string to the
37
+ script output.
38
+
39
+ """
40
+ context.configure(
41
+ url=get_db_url(),
42
+ target_metadata=target_metadata,
43
+ literal_binds=True,
44
+ dialect_opts={"paramstyle": "named"},
45
+ )
46
+
47
+ with context.begin_transaction():
48
+ context.run_migrations()
49
+
50
+
51
+ def run_migrations_online() -> None:
52
+ """Run migrations in 'online' mode.
53
+
54
+ In this scenario we need to create an Engine
55
+ and associate a connection with the context.
56
+
57
+ """
58
+ connectable = get_engine()
59
+ with connectable.connect() as connection:
60
+ context.configure(connection=connection, target_metadata=target_metadata)
61
+ with context.begin_transaction():
62
+ context.run_migrations()
63
+
64
+
65
+ if context.is_offline_mode():
66
+ run_migrations_offline()
67
+ else:
68
+ run_migrations_online()
@@ -0,0 +1,47 @@
1
+ # SPDX-FileCopyrightText: Magenta ApS
2
+ # SPDX-License-Identifier: MPL-2.0
3
+ """Add Payload table
4
+
5
+ Revision ID: 26d00ae9c67f
6
+ Revises:
7
+ Create Date: 2023-09-29 12:31:28.477508
8
+
9
+ """
10
+ from typing import Sequence
11
+ from typing import Union
12
+
13
+ import sqlalchemy as sa
14
+ from alembic import op
15
+ from sqlalchemy.dialects import postgresql
16
+
17
+ # revision identifiers, used by Alembic.
18
+ revision: str = "26d00ae9c67f"
19
+ down_revision: Union[str, None] = None
20
+ branch_labels: Union[str, Sequence[str], None] = None
21
+ depends_on: Union[str, Sequence[str], None] = None
22
+
23
+
24
+ def upgrade() -> None:
25
+ # ### commands auto generated by Alembic - please adjust! ###
26
+ op.create_table(
27
+ "payload",
28
+ sa.Column("id", postgresql.UUID(as_uuid=True), nullable=False),
29
+ sa.Column(
30
+ "timestamp",
31
+ sa.DateTime(timezone=True),
32
+ server_default=sa.text("now()"),
33
+ nullable=True,
34
+ ),
35
+ sa.Column("full_url", sa.TEXT(), nullable=True),
36
+ sa.Column("params", sa.TEXT(), nullable=True),
37
+ sa.Column("response", sa.TEXT(), nullable=True),
38
+ sa.Column("status_code", sa.Integer(), nullable=True),
39
+ sa.PrimaryKeyConstraint("id"),
40
+ )
41
+ # ### end Alembic commands ###
42
+
43
+
44
+ def downgrade() -> None:
45
+ # ### commands auto generated by Alembic - please adjust! ###
46
+ op.drop_table("payload")
47
+ # ### end Alembic commands ###
@@ -0,0 +1,40 @@
1
+ # SPDX-FileCopyrightText: Magenta ApS
2
+ # SPDX-License-Identifier: MPL-2.0
3
+ from uuid import UUID
4
+
5
+ from sqlalchemy.orm import sessionmaker
6
+
7
+ from .engine import get_engine
8
+ from .models import Payload
9
+
10
+
11
+ Session = sessionmaker()
12
+
13
+
14
+ def log_payload(
15
+ request_uuid: UUID,
16
+ full_url: str,
17
+ params: str,
18
+ response: str,
19
+ status_code: int,
20
+ ) -> None:
21
+ """Log a given SD payload to the payload database
22
+
23
+ Args:
24
+ request_uuid: Unique UUID of this API request. Must be generated by the caller.
25
+ full_url: Full URL of API endpoint called, e.g. containing the SD server name.
26
+ params: Stringified version of the `payload` variable in `sd_lookup`.
27
+ response: The raw/unparsed XML response from the SD API endpoint called.
28
+ status_code: The HTTP status code from the SD API endpoint called.
29
+ """
30
+ Session.configure(bind=get_engine())
31
+ session = Session()
32
+ payload = Payload(
33
+ id=request_uuid,
34
+ full_url=full_url,
35
+ params=params,
36
+ response=response,
37
+ status_code=status_code,
38
+ )
39
+ session.add(payload)
40
+ session.commit()
@@ -0,0 +1,14 @@
1
+ # SPDX-FileCopyrightText: Magenta ApS
2
+ # SPDX-License-Identifier: MPL-2.0
3
+ import os
4
+
5
+ from sqlalchemy import create_engine
6
+ from sqlalchemy.engine import Engine
7
+
8
+
9
+ def get_db_url() -> str:
10
+ return f"postgresql+psycopg2://{os.environ['APP_DBUSER']}:{os.environ['APP_DBPASSWORD']}@{os.environ['PGHOST']}/{os.environ['APP_DATABASE']}"
11
+
12
+
13
+ def get_engine() -> Engine:
14
+ return create_engine(get_db_url())
@@ -0,0 +1,23 @@
1
+ # SPDX-FileCopyrightText: Magenta ApS
2
+ # SPDX-License-Identifier: MPL-2.0
3
+ from sqlalchemy import Column
4
+ from sqlalchemy import DateTime
5
+ from sqlalchemy import Integer
6
+ from sqlalchemy.dialects.postgresql import TEXT
7
+ from sqlalchemy.dialects.postgresql import UUID
8
+ from sqlalchemy.orm import declarative_base
9
+ from sqlalchemy.sql import func
10
+
11
+
12
+ Base = declarative_base()
13
+
14
+
15
+ class Payload(Base): # type: ignore
16
+ __tablename__ = "payload"
17
+
18
+ id = Column(UUID(as_uuid=True), primary_key=True)
19
+ timestamp = Column(DateTime(timezone=True), server_default=func.now())
20
+ full_url = Column(TEXT)
21
+ params = Column(TEXT)
22
+ response = Column(TEXT)
23
+ status_code = Column(Integer)
@@ -1,10 +1,12 @@
1
1
  import datetime
2
2
  import json
3
+ import uuid
3
4
  from typing import Any
4
5
  from typing import Optional
5
6
  from typing import List
6
7
  from typing import OrderedDict
7
8
  from uuid import UUID
9
+ from uuid import uuid4
8
10
 
9
11
  import requests
10
12
  from os2mo_helpers.mora_helpers import MoraHelper
@@ -77,8 +79,13 @@ class FixDepartments:
77
79
  """
78
80
  inst_id = self.settings.sd_institution_identifier
79
81
  params = {"UUIDIndicator": "true", "InstitutionIdentifier": inst_id}
82
+ request_uuid = uuid4()
83
+ logger.info("get_institution", request_uuid=request_uuid)
80
84
  institution_info = sd_lookup(
81
- "GetInstitution20111201", settings=self.settings, params=params
85
+ "GetInstitution20111201",
86
+ settings=self.settings,
87
+ params=params,
88
+ request_uuid=request_uuid,
82
89
  )
83
90
  institution = institution_info["Region"]["Institution"]
84
91
  institution_uuid = institution["InstitutionUUIDIdentifier"]
@@ -262,8 +269,13 @@ class FixDepartments:
262
269
  if uuid is None and shortname is None:
263
270
  raise Exception("Provide either uuid or shortname")
264
271
 
272
+ request_uuid = uuid4()
273
+ logger.info("get_department", request_uuid=request_uuid)
265
274
  department_info = sd_lookup(
266
- "GetDepartment20111201", settings=self.settings, params=params
275
+ "GetDepartment20111201",
276
+ settings=self.settings,
277
+ params=params,
278
+ request_uuid=request_uuid,
267
279
  )
268
280
  department = department_info.get("Department")
269
281
  if department is None:
@@ -343,9 +355,17 @@ class FixDepartments:
343
355
  for time_delta in time_deltas:
344
356
  effective_date = validity_date + datetime.timedelta(days=time_delta)
345
357
  params["EffectiveDate"] = (effective_date.strftime("%d.%m.%Y"),)
346
-
358
+ request_uuid = uuid4()
359
+ logger.info(
360
+ "_read_department_engagements",
361
+ request_uuid=request_uuid,
362
+ time_delta=time_delta,
363
+ )
347
364
  employments = sd_lookup(
348
- "GetEmployment20111201", settings=self.settings, params=params
365
+ "GetEmployment20111201",
366
+ settings=self.settings,
367
+ params=params,
368
+ request_uuid=request_uuid,
349
369
  )
350
370
  people = employments.get("Person", [])
351
371
  if not isinstance(people, list):
@@ -467,8 +487,13 @@ class FixDepartments:
467
487
  "EffectiveDate": validity_date.strftime("%d.%m.%Y"),
468
488
  "DepartmentUUIDIdentifier": unit_uuid,
469
489
  }
490
+ request_uuid = uuid4()
491
+ logger.info("get_parent", request_uuid=request_uuid)
470
492
  parent_response = sd_lookup(
471
- "GetDepartmentParent20190701", settings=self.settings, params=params
493
+ "GetDepartmentParent20190701",
494
+ settings=self.settings,
495
+ params=params,
496
+ request_uuid=request_uuid,
472
497
  )
473
498
  if "DepartmentParent" not in parent_response:
474
499
  logger.error(
@@ -3,6 +3,7 @@ import logging
3
3
  import pathlib
4
4
  import sqlite3
5
5
  import sys
6
+ import uuid
6
7
  from functools import lru_cache
7
8
  from itertools import tee
8
9
  from operator import itemgetter
@@ -314,7 +315,15 @@ class ChangeAtSD:
314
315
  "DeactivationDate": "31.12.9999",
315
316
  }
316
317
  )
317
- response = sd_lookup(url, settings=self.settings, params=params)
318
+
319
+ request_uuid = uuid.uuid4()
320
+ logger.info("read_employment_changed", request_uuid=request_uuid)
321
+ response = sd_lookup(
322
+ url,
323
+ settings=self.settings,
324
+ params=params,
325
+ request_uuid=request_uuid,
326
+ )
318
327
 
319
328
  employment_response = ensure_list(response.get("Person", []))
320
329
 
@@ -352,8 +361,15 @@ class ChangeAtSD:
352
361
  params["DeactivationDate"] = to_date.strftime("%d.%m.%Y")
353
362
  params["DeactivationTime"] = to_date.strftime("%H:%M")
354
363
 
364
+ request_uuid = uuid.uuid4()
365
+ logger.info("get_sd_persons_changed", request_uuid=request_uuid)
355
366
  url = "GetPersonChangedAtDate20111201"
356
- response = sd_lookup(url, settings=self.settings, params=params)
367
+ response = sd_lookup(
368
+ url,
369
+ settings=self.settings,
370
+ params=params,
371
+ request_uuid=request_uuid,
372
+ )
357
373
  persons_changed = ensure_list(response.get("Person", []))
358
374
  return persons_changed
359
375
 
@@ -380,7 +396,14 @@ class ChangeAtSD:
380
396
  "PostalAddressIndicator": "false",
381
397
  }
382
398
  url = "GetPerson20111201"
383
- response = sd_lookup(url, settings=self.settings, params=params)
399
+ request_uuid = uuid.uuid4()
400
+ logger.info("get_sd_person", request_uuid=request_uuid)
401
+ response = sd_lookup(
402
+ url,
403
+ settings=self.settings,
404
+ params=params,
405
+ request_uuid=request_uuid,
406
+ )
384
407
  person = ensure_list(response.get("Person", []))
385
408
  return person
386
409
 
@@ -969,7 +992,14 @@ class ChangeAtSD:
969
992
  "UUIDIndicator": "true",
970
993
  "DepartmentIdentifier": department["DepartmentIdentifier"],
971
994
  }
972
- response = sd_lookup(url, settings=self.settings, params=params)
995
+ request_uuid = uuid.uuid4()
996
+ logger.info("edit_engagement_department", request_uuid=request_uuid)
997
+ response = sd_lookup(
998
+ url,
999
+ settings=self.settings,
1000
+ params=params,
1001
+ request_uuid=request_uuid,
1002
+ )
973
1003
  logger.warning("GetDepartment returned", response=response)
974
1004
  org_unit = response["Department"]["DepartmentUUIDIdentifier"]
975
1005
  if org_unit is None:
@@ -6,14 +6,19 @@
6
6
  # angiv uuider for de berørte på kommandolinien
7
7
  import datetime
8
8
  import sys
9
+ import uuid
9
10
 
10
11
  import click
11
12
 
12
13
  from .config import get_changed_at_settings
14
+ from .log import get_logger
13
15
  from .sd_changed_at import ChangeAtSD
14
16
  from .sd_common import sd_lookup
15
17
 
16
18
 
19
+ logger = get_logger()
20
+
21
+
17
22
  def read_person(cat, cpr):
18
23
  params = {
19
24
  "EffectiveDate": cat.from_date.strftime("%d.%m.%Y"),
@@ -24,7 +29,9 @@ def read_person(cat, cpr):
24
29
  "PostalAddressIndicator": "false",
25
30
  }
26
31
  url = "GetPerson20111201"
27
- response = sd_lookup(url, params=params)
32
+ request_uuid = uuid.uuid4()
33
+ logger.info("read_person", request_uuid=request_uuid)
34
+ response = sd_lookup(url, params=params, request_uuid=request_uuid)
28
35
  person = response.get("Person", [])
29
36
 
30
37
  if not isinstance(person, list):
@@ -12,6 +12,7 @@ from typing import Union
12
12
 
13
13
  import requests
14
14
  import xmltodict
15
+ from payload_db import log_payload
15
16
  from ra_utils.load_settings import load_settings
16
17
 
17
18
  from .config import CommonSettings
@@ -43,6 +44,7 @@ def sd_lookup(
43
44
  url: str,
44
45
  settings: Optional[CommonSettings] = None,
45
46
  params: Optional[Dict[str, Any]] = None,
47
+ request_uuid: Optional[uuid.UUID] = None,
46
48
  ) -> OrderedDict:
47
49
  """Fire a requests against SD."""
48
50
  logger.info("Retrieve: {}".format(url))
@@ -75,9 +77,16 @@ def sd_lookup(
75
77
  auth=auth,
76
78
  )
77
79
 
78
- # This line logs CPR numbers - instead we will persist the SD payloads
79
- # in a DB (see Redmine #57093)
80
- # logger.debug("Response: {}".format(response.text))
80
+ try:
81
+ log_payload(
82
+ request_uuid=request_uuid,
83
+ full_url=full_url,
84
+ params=str(payload),
85
+ response=response.text,
86
+ status_code=response.status_code,
87
+ )
88
+ except Exception:
89
+ logger.exception("could not save SD response to payload database")
81
90
 
82
91
  dict_response = xmltodict.parse(response.text)
83
92
 
@@ -279,5 +288,12 @@ def read_employment_at(
279
288
  if employment_id:
280
289
  params.update({"EmploymentIdentifier": employment_id})
281
290
 
282
- response = sd_lookup(url, settings=settings, params=params)
291
+ request_uuid = uuid.uuid4()
292
+ logger.info("read_employment_at", request_uuid=request_uuid)
293
+ response = sd_lookup(
294
+ url,
295
+ settings=settings,
296
+ params=params,
297
+ request_uuid=request_uuid,
298
+ )
283
299
  return response.get("Person")
@@ -1,4 +1,5 @@
1
1
  import datetime
2
+ import uuid
2
3
  from datetime import date
3
4
  from functools import partial
4
5
  from operator import itemgetter
@@ -25,6 +26,7 @@ from tqdm import tqdm
25
26
 
26
27
  from . import sd_payloads
27
28
  from .config import get_importer_settings
29
+ from .log import get_logger
28
30
  from .sd_changed_at import ChangeAtSD
29
31
  from .sd_common import EmploymentStatus
30
32
  from .sd_common import mora_assert
@@ -32,6 +34,9 @@ from .sd_common import primary_types
32
34
  from .sd_common import sd_lookup
33
35
 
34
36
 
37
+ logger = get_logger()
38
+
39
+
35
40
  def fetch_user_employments(cpr: str) -> List:
36
41
  # Notice, this will not get future engagements
37
42
  params = {
@@ -47,8 +52,14 @@ def fetch_user_employments(cpr: str) -> List:
47
52
  "SalaryCodeGroupIndicator": "false",
48
53
  "EffectiveDate": date.today().strftime("%d.%m.%Y"),
49
54
  }
50
-
51
- sd_employments_response = sd_lookup("GetEmployment20111201", None, params)
55
+ request_uuid = uuid.uuid4()
56
+ logger.info("fetch_user_employments", request_uuid=request_uuid)
57
+ sd_employments_response = sd_lookup(
58
+ "GetEmployment20111201",
59
+ settings=None,
60
+ params=params,
61
+ request_uuid=request_uuid,
62
+ )
52
63
  if "Person" not in sd_employments_response:
53
64
  return []
54
65
 
@@ -11,6 +11,7 @@ from operator import itemgetter
11
11
  from typing import Any, OrderedDict
12
12
  from typing import Dict
13
13
  from typing import Optional
14
+ from uuid import uuid4
14
15
 
15
16
  import click
16
17
  from anytree import Node
@@ -207,8 +208,13 @@ class SdImport:
207
208
  "UUIDIndicator": "true",
208
209
  "EmploymentDepartmentIndicator": "false",
209
210
  }
211
+ request_uuid = uuid4()
212
+ logger.info("_read_department_info", request_uuid=request_uuid)
210
213
  departments = sd_lookup(
211
- "GetDepartment20111201", settings=self.settings, params=params
214
+ "GetDepartment20111201",
215
+ settings=self.settings,
216
+ params=params,
217
+ request_uuid=request_uuid,
212
218
  )
213
219
 
214
220
  for department in departments["Department"]:
@@ -388,7 +394,14 @@ class SdImport:
388
394
  "InstitutionIdentifier": self.settings.sd_institution_identifier,
389
395
  "UUIDIndicator": "true",
390
396
  }
391
- r = sd_lookup("GetInstitution20111201", settings=self.settings, params=params)
397
+ request_uuid = uuid4()
398
+ logger.info("_get_institution", request_uuid=request_uuid)
399
+ r = sd_lookup(
400
+ "GetInstitution20111201",
401
+ settings=self.settings,
402
+ params=params,
403
+ request_uuid=request_uuid,
404
+ )
392
405
  return uuid.UUID(r["Region"]["Institution"]["InstitutionUUIDIdentifier"])
393
406
 
394
407
  def _create_org_tree_structure(self):
@@ -463,16 +476,26 @@ class SdImport:
463
476
  "PostalAddressIndicator": "false",
464
477
  "EffectiveDate": self.import_date,
465
478
  }
479
+ request_uuid = uuid4()
480
+ logger.info("add_people: active_people", request_uuid=request_uuid)
466
481
  active_people = sd_lookup(
467
- "GetPerson20111201", settings=self.settings, params=params
482
+ "GetPerson20111201",
483
+ settings=self.settings,
484
+ params=params,
485
+ request_uuid=request_uuid,
468
486
  )
469
487
  if not isinstance(active_people["Person"], list):
470
488
  active_people["Person"] = [active_people["Person"]]
471
489
 
472
490
  params["StatusActiveIndicator"] = False
473
491
  params["StatusPassiveIndicator"] = True
492
+ request_uuid = uuid4()
493
+ logger.info("add_people: passive_people", request_uuid=request_uuid)
474
494
  passive_people = sd_lookup(
475
- "GetPerson20111201", settings=self.settings, params=params
495
+ "GetPerson20111201",
496
+ settings=self.settings,
497
+ params=params,
498
+ request_uuid=request_uuid,
476
499
  )
477
500
  if not isinstance(passive_people["Person"], list):
478
501
  passive_people["Person"] = [passive_people["Person"]]
@@ -569,8 +592,13 @@ class SdImport:
569
592
  "DeactivationDate": self.import_date,
570
593
  "UUIDIndicator": "true",
571
594
  }
595
+ request_uuid = uuid4()
596
+ logger.info("create_ou_tree", request_uuid=request_uuid)
572
597
  organisation = sd_lookup(
573
- "GetOrganization20111201", settings=self.settings, params=params
598
+ "GetOrganization20111201",
599
+ settings=self.settings,
600
+ params=params,
601
+ request_uuid=request_uuid,
574
602
  )
575
603
  departments = organisation["Organization"]["DepartmentReference"]
576
604
 
@@ -1,5 +1,6 @@
1
1
  import logging
2
2
  import sys
3
+ import uuid
3
4
 
4
5
  import click
5
6
  import requests
@@ -99,8 +100,15 @@ class JobIdSync:
99
100
  params = {
100
101
  "JobPositionIdentifier": job_pos_id,
101
102
  }
103
+ request_uuid = uuid.uuid4()
104
+ logger.info("_get_job_pos_id_from_sd", request_uuid=request_uuid)
102
105
  try:
103
- job_pos_response = sd_lookup("GetProfession20080201", self.settings, params)
106
+ job_pos_response = sd_lookup(
107
+ "GetProfession20080201",
108
+ settings=self.settings,
109
+ params=params,
110
+ request_uuid=request_uuid,
111
+ )
104
112
  except Exception: # TODO: Be specific here
105
113
  logger.info("This job_position could not be found in SD")
106
114
  return None
@@ -1,4 +1,5 @@
1
1
  import json
2
+ import uuid
2
3
  from datetime import datetime
3
4
  from itertools import starmap
4
5
  from operator import itemgetter
@@ -7,11 +8,15 @@ import click
7
8
  from more_itertools import flatten
8
9
  from os2mo_helpers.mora_helpers import MoraHelper
9
10
 
11
+ from .log import get_logger
10
12
  from .sd_common import EmploymentStatus
11
13
  from .sd_common import load_settings
12
14
  from .sd_common import sd_lookup
13
15
 
14
16
 
17
+ logger = get_logger()
18
+
19
+
15
20
  def progress_iterator(elements, outputter, mod=10):
16
21
  total = len(elements)
17
22
  for i, element in enumerate(elements, start=1):
@@ -150,7 +155,13 @@ class TestMOAgainstSd(object):
150
155
  "SalaryCodeGroupIndicator": "false",
151
156
  "EffectiveDate": self.date.strftime("%d.%m.%Y"),
152
157
  }
153
- sd_employments_response = sd_lookup("GetEmployment20111201", params)
158
+ request_uuid = uuid.uuid4()
159
+ logger.info("check_user", request_uuid=request_uuid)
160
+ sd_employments_response = sd_lookup(
161
+ "GetEmployment20111201",
162
+ params=params,
163
+ request_uuid=request_uuid,
164
+ )
154
165
  if "Person" not in sd_employments_response:
155
166
  return mo_uuid, {
156
167
  "uuid": mo_uuid,
@@ -1,13 +1,18 @@
1
1
  import logging
2
+ import uuid
2
3
  from uuid import UUID
3
4
 
4
5
  import click
5
6
  from pydantic import ValidationError
6
7
 
7
8
  from .config import get_changed_at_settings
9
+ from .log import get_logger
8
10
  from .sd_common import sd_lookup
9
11
 
10
12
 
13
+ logger = get_logger()
14
+
15
+
11
16
  class TestSdConnectivity(object):
12
17
  def __init__(self):
13
18
  self.validation_error = None
@@ -36,11 +41,14 @@ class TestSdConnectivity(object):
36
41
  "UUIDIndicator": "true",
37
42
  "InstitutionIdentifier": self.settings.sd_institution_identifier,
38
43
  }
44
+ request_uuid = uuid.uuid4()
45
+ logger.info("_check_contact_to_sd", request_uuid=request_uuid)
39
46
  try:
40
47
  institution_info = sd_lookup(
41
48
  "GetInstitution20111201",
42
49
  settings=self.settings,
43
50
  params=params,
51
+ request_uuid=request_uuid,
44
52
  )
45
53
  except Exception:
46
54
  logging.exception("Fejl i kontakt til SD Løn")