dipex 5.7.0__tar.gz → 5.7.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. {dipex-5.7.0 → dipex-5.7.2}/PKG-INFO +1 -1
  2. {dipex-5.7.0 → dipex-5.7.2}/exporters/sql_export/lora_cache.py +2 -2
  3. {dipex-5.7.0 → dipex-5.7.2}/pyproject.toml +1 -1
  4. dipex-5.7.0/integrations/SD_Lon/alembic/env.py +0 -68
  5. dipex-5.7.0/integrations/SD_Lon/alembic/versions/26d00ae9c67f_add_payload_table.py +0 -47
  6. dipex-5.7.0/integrations/SD_Lon/payload_db/__init__.py +0 -40
  7. dipex-5.7.0/integrations/SD_Lon/payload_db/engine.py +0 -14
  8. dipex-5.7.0/integrations/SD_Lon/payload_db/models.py +0 -23
  9. dipex-5.7.0/integrations/SD_Lon/sdlon/config.py +0 -201
  10. dipex-5.7.0/integrations/SD_Lon/sdlon/date_utils.py +0 -181
  11. dipex-5.7.0/integrations/SD_Lon/sdlon/employees.py +0 -51
  12. dipex-5.7.0/integrations/SD_Lon/sdlon/engagement.py +0 -144
  13. dipex-5.7.0/integrations/SD_Lon/sdlon/exceptions.py +0 -2
  14. dipex-5.7.0/integrations/SD_Lon/sdlon/fix_departments.py +0 -568
  15. dipex-5.7.0/integrations/SD_Lon/sdlon/graphql.py +0 -36
  16. dipex-5.7.0/integrations/SD_Lon/sdlon/it_systems.py +0 -131
  17. dipex-5.7.0/integrations/SD_Lon/sdlon/log.py +0 -66
  18. dipex-5.7.0/integrations/SD_Lon/sdlon/main.py +0 -129
  19. dipex-5.7.0/integrations/SD_Lon/sdlon/models.py +0 -42
  20. dipex-5.7.0/integrations/SD_Lon/sdlon/scripts/fix_monthly_hourly_divide.py +0 -223
  21. dipex-5.7.0/integrations/SD_Lon/sdlon/scripts/fix_status8.py +0 -306
  22. dipex-5.7.0/integrations/SD_Lon/sdlon/scripts/generate_org_unit_level_uuid.py +0 -36
  23. dipex-5.7.0/integrations/SD_Lon/sdlon/sd_changed_at.py +0 -1645
  24. dipex-5.7.0/integrations/SD_Lon/sdlon/sd_changed_at_redo.py +0 -75
  25. dipex-5.7.0/integrations/SD_Lon/sdlon/sd_cli.py +0 -29
  26. dipex-5.7.0/integrations/SD_Lon/sdlon/sd_common.py +0 -299
  27. dipex-5.7.0/integrations/SD_Lon/sdlon/sd_fixup.py +0 -475
  28. dipex-5.7.0/integrations/SD_Lon/sdlon/sd_importer.py +0 -906
  29. dipex-5.7.0/integrations/SD_Lon/sdlon/sd_log_analyzer.py +0 -223
  30. dipex-5.7.0/integrations/SD_Lon/sdlon/sd_payloads.py +0 -164
  31. dipex-5.7.0/integrations/SD_Lon/sdlon/sd_to_pydantic.py +0 -38
  32. dipex-5.7.0/integrations/SD_Lon/sdlon/skip.py +0 -61
  33. dipex-5.7.0/integrations/SD_Lon/sdlon/sync_job_id.py +0 -255
  34. dipex-5.7.0/integrations/SD_Lon/sdlon/test_mo_against_sd.py +0 -359
  35. dipex-5.7.0/integrations/SD_Lon/sdlon/test_sd_connectivity.py +0 -82
  36. dipex-5.7.0/integrations/SD_Lon/sdtool/config.py +0 -62
  37. dipex-5.7.0/integrations/SD_Lon/sdtool/main.py +0 -156
  38. dipex-5.7.0/integrations/SD_Lon/tests/__init__.py +0 -9
  39. dipex-5.7.0/integrations/SD_Lon/tests/fixtures.py +0 -746
  40. dipex-5.7.0/integrations/SD_Lon/tests/org_manipulations.py +0 -360
  41. dipex-5.7.0/integrations/SD_Lon/tests/payload_db/test_engine.py +0 -34
  42. dipex-5.7.0/integrations/SD_Lon/tests/payload_db/test_log_payload.py +0 -33
  43. dipex-5.7.0/integrations/SD_Lon/tests/sdtool/test_app.py +0 -61
  44. dipex-5.7.0/integrations/SD_Lon/tests/sdtool/test_config.py +0 -102
  45. dipex-5.7.0/integrations/SD_Lon/tests/sdtool/utils.py +0 -59
  46. dipex-5.7.0/integrations/SD_Lon/tests/test_config.py +0 -282
  47. dipex-5.7.0/integrations/SD_Lon/tests/test_date_utils.py +0 -374
  48. dipex-5.7.0/integrations/SD_Lon/tests/test_employee.py +0 -57
  49. dipex-5.7.0/integrations/SD_Lon/tests/test_engagement.py +0 -135
  50. dipex-5.7.0/integrations/SD_Lon/tests/test_fix_departments.py +0 -522
  51. dipex-5.7.0/integrations/SD_Lon/tests/test_graphql.py +0 -23
  52. dipex-5.7.0/integrations/SD_Lon/tests/test_it_systems.py +0 -121
  53. dipex-5.7.0/integrations/SD_Lon/tests/test_log.py +0 -12
  54. dipex-5.7.0/integrations/SD_Lon/tests/test_main.py +0 -61
  55. dipex-5.7.0/integrations/SD_Lon/tests/test_sd_changed_at.py +0 -1616
  56. dipex-5.7.0/integrations/SD_Lon/tests/test_sd_common.py +0 -75
  57. dipex-5.7.0/integrations/SD_Lon/tests/test_sd_importer.py +0 -717
  58. dipex-5.7.0/integrations/SD_Lon/tests/test_sd_log_analyzer.py +0 -221
  59. dipex-5.7.0/integrations/SD_Lon/tests/test_sd_to_pydantic.py +0 -94
  60. dipex-5.7.0/integrations/SD_Lon/tests/test_skip.py +0 -62
  61. dipex-5.7.0/integrations/SD_Lon/tests/test_sync_job_id.py +0 -31
  62. dipex-5.7.0/integrations/aarhus/tests/__init__.py +0 -0
  63. dipex-5.7.0/integrations/ad_integration/__init__.py +0 -0
  64. dipex-5.7.0/integrations/ad_integration/tests/__init__.py +0 -0
  65. dipex-5.7.0/integrations/calculate_primary/__init__.py +0 -0
  66. dipex-5.7.0/integrations/calculate_primary/tests/__init__.py +0 -0
  67. {dipex-5.7.0 → dipex-5.7.2}/exporters/sql_export/__init__.py +0 -0
  68. {dipex-5.7.0 → dipex-5.7.2}/exporters/sql_export/gql_lora_cache_async.py +0 -0
  69. {dipex-5.7.0 → dipex-5.7.2}/exporters/sql_export/lc_for_jobs_db.py +0 -0
  70. {dipex-5.7.0 → dipex-5.7.2}/exporters/sql_export/log.py +0 -0
  71. {dipex-5.7.0 → dipex-5.7.2}/exporters/sql_export/main.py +0 -0
  72. {dipex-5.7.0 → dipex-5.7.2}/exporters/sql_export/old_lora_cache.py +0 -0
  73. {dipex-5.7.0 → dipex-5.7.2}/exporters/sql_export/sql_export.py +0 -0
  74. {dipex-5.7.0 → dipex-5.7.2}/exporters/sql_export/sql_table_defs.py +0 -0
  75. {dipex-5.7.0 → dipex-5.7.2}/exporters/sql_export/sql_url.py +0 -0
  76. {dipex-5.7.0 → dipex-5.7.2}/exporters/sql_export/trigger.py +0 -0
  77. {dipex-5.7.0 → dipex-5.7.2}/exporters/utils/priority_by_class.py +0 -0
  78. {dipex-5.7.0/integrations/SD_Lon/sdlon → dipex-5.7.2/integrations}/__init__.py +0 -0
  79. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/config.py +0 -0
  80. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/dar_helper.py +0 -0
  81. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/initial.py +0 -0
  82. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/initial_classes.py +0 -0
  83. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/los_files.py +0 -0
  84. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/los_import.py +0 -0
  85. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/los_leder.py +0 -0
  86. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/los_org.py +0 -0
  87. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/los_pers.py +0 -0
  88. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/los_stam.py +0 -0
  89. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/payloads.py +0 -0
  90. {dipex-5.7.0/integrations/SD_Lon/sdlon/scripts → dipex-5.7.2/integrations/aarhus/tests}/__init__.py +0 -0
  91. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/tests/conftest.py +0 -0
  92. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/tests/helpers.py +0 -0
  93. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/tests/strategies.py +0 -0
  94. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/tests/test_config.py +0 -0
  95. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/tests/test_initial.py +0 -0
  96. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/tests/test_los_files.py +0 -0
  97. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/tests/test_los_import.py +0 -0
  98. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/tests/test_los_leder.py +0 -0
  99. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/tests/test_los_org.py +0 -0
  100. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/tests/test_los_pers.py +0 -0
  101. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/tests/test_los_stam.py +0 -0
  102. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/tests/test_payloads.py +0 -0
  103. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/tests/test_util.py +0 -0
  104. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/util.py +0 -0
  105. {dipex-5.7.0 → dipex-5.7.2}/integrations/aarhus/uuids.py +0 -0
  106. {dipex-5.7.0/integrations/SD_Lon/sdtool → dipex-5.7.2/integrations/ad_integration}/__init__.py +0 -0
  107. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/ad_common.py +0 -0
  108. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/ad_exceptions.py +0 -0
  109. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/ad_fix_enddate.py +0 -0
  110. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/ad_jinja_filters.py +0 -0
  111. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/ad_life_cycle.py +0 -0
  112. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/ad_logger.py +0 -0
  113. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/ad_reader.py +0 -0
  114. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/ad_sync.py +0 -0
  115. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/ad_template_engine.py +0 -0
  116. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/ad_templates.py +0 -0
  117. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/ad_writer.py +0 -0
  118. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/import_ad_group_into_mo.py +0 -0
  119. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/mo_to_ad_sync.py +0 -0
  120. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/payloads.py +0 -0
  121. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/read_ad_conf_settings.py +0 -0
  122. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/sync_mo_uuid_to_ad.py +0 -0
  123. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/test_connectivity.py +0 -0
  124. {dipex-5.7.0/integrations/SD_Lon/tests/payload_db → dipex-5.7.2/integrations/ad_integration/tests}/__init__.py +0 -0
  125. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/mocks.py +0 -0
  126. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/name_simulator.py +0 -0
  127. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_ad_common.py +0 -0
  128. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_ad_fix_enddate.py +0 -0
  129. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_ad_jinja_filters.py +0 -0
  130. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_ad_life_cycle.py +0 -0
  131. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_ad_logger.py +0 -0
  132. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_ad_reader.py +0 -0
  133. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_ad_sync.py +0 -0
  134. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_ad_writer.py +0 -0
  135. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_dot_mapping.py +0 -0
  136. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_first_included.py +0 -0
  137. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_import_ad_group_into_mo.py +0 -0
  138. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_location_element.py +0 -0
  139. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_mo_data_source.py +0 -0
  140. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_mo_to_ad_sync.py +0 -0
  141. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_morestsource.py +0 -0
  142. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_read_ad_conf_settings.py +0 -0
  143. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_recursive_dict_update.py +0 -0
  144. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_sync_mo_uuid_to_ad.py +0 -0
  145. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_usernames.py +0 -0
  146. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/tests/test_utils.py +0 -0
  147. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/user_names.py +0 -0
  148. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/username_rules/method_2.py +0 -0
  149. {dipex-5.7.0 → dipex-5.7.2}/integrations/ad_integration/utils.py +0 -0
  150. {dipex-5.7.0/integrations/SD_Lon/tests/sdtool → dipex-5.7.2/integrations/calculate_primary}/__init__.py +0 -0
  151. {dipex-5.7.0 → dipex-5.7.2}/integrations/calculate_primary/calculate_primary.py +0 -0
  152. {dipex-5.7.0 → dipex-5.7.2}/integrations/calculate_primary/common.py +0 -0
  153. {dipex-5.7.0 → dipex-5.7.2}/integrations/calculate_primary/default.py +0 -0
  154. {dipex-5.7.0 → dipex-5.7.2}/integrations/calculate_primary/opus.py +0 -0
  155. {dipex-5.7.0 → dipex-5.7.2}/integrations/calculate_primary/sd.py +0 -0
  156. {dipex-5.7.0/integrations → dipex-5.7.2/integrations/calculate_primary/tests}/__init__.py +0 -0
  157. {dipex-5.7.0 → dipex-5.7.2}/integrations/calculate_primary/tests/test_primary.py +0 -0
  158. {dipex-5.7.0 → dipex-5.7.2}/integrations/cpr_mapper.py +0 -0
  159. {dipex-5.7.0 → dipex-5.7.2}/integrations/dawa_helper.py +0 -0
  160. {dipex-5.7.0 → dipex-5.7.2}/integrations/kle/__init__.py +0 -0
  161. {dipex-5.7.0 → dipex-5.7.2}/integrations/kle/kle_import.py +0 -0
  162. {dipex-5.7.0 → dipex-5.7.2}/integrations/kle/kle_import_export.py +0 -0
  163. {dipex-5.7.0 → dipex-5.7.2}/integrations/kle/kle_xlsx.py +0 -0
  164. {dipex-5.7.0 → dipex-5.7.2}/integrations/kle/payloads.py +0 -0
  165. {dipex-5.7.0 → dipex-5.7.2}/integrations/opus/clear_and_import_opus.py +0 -0
  166. {dipex-5.7.0 → dipex-5.7.2}/integrations/opus/opus_diff_import.py +0 -0
  167. {dipex-5.7.0 → dipex-5.7.2}/integrations/opus/opus_exceptions.py +0 -0
  168. {dipex-5.7.0 → dipex-5.7.2}/integrations/opus/opus_file_reader.py +0 -0
  169. {dipex-5.7.0 → dipex-5.7.2}/integrations/opus/opus_helpers.py +0 -0
  170. {dipex-5.7.0 → dipex-5.7.2}/integrations/opus/opus_reimport_one.py +0 -0
  171. {dipex-5.7.0 → dipex-5.7.2}/integrations/opus/org_tree_print/main.py +0 -0
  172. {dipex-5.7.0 → dipex-5.7.2}/integrations/opus/payloads.py +0 -0
  173. {dipex-5.7.0 → dipex-5.7.2}/integrations/opus/tests/test_opus_diff_import.py +0 -0
  174. {dipex-5.7.0 → dipex-5.7.2}/integrations/opus/tests/test_opus_file_reader.py +0 -0
  175. {dipex-5.7.0 → dipex-5.7.2}/integrations/opus/tests/test_opus_helpers.py +0 -0
  176. {dipex-5.7.0 → dipex-5.7.2}/integrations/rundb/db_overview.py +0 -0
  177. {dipex-5.7.0 → dipex-5.7.2}/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.7.0
3
+ Version: 5.7.2
4
4
  Summary: OS2mo-data-import-and-export
5
5
  Home-page: https://magenta.dk/
6
6
  License: MPL-2.0
@@ -19,8 +19,8 @@ PICKLE_PROTOCOL = pickle.DEFAULT_PROTOCOL
19
19
 
20
20
 
21
21
  def get_cache(resolve_dar=True, full_history=False, skip_past=False, settings=None):
22
- if GqlLoraCacheSettings().sentry_dsn:
23
- sentry_sdk.init(dsn=GqlLoraCacheSettings().sentry_dsn)
22
+ if GqlLoraCacheSettings().job_settings.sentry_dsn:
23
+ sentry_sdk.init(dsn=GqlLoraCacheSettings().job_settings.sentry_dsn)
24
24
 
25
25
  if GqlLoraCacheSettings().use_new_cache:
26
26
  return GQLLoraCache(
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "DIPEX"
3
- version = "5.7.0"
3
+ version = "5.7.2"
4
4
  authors = ["Magenta ApS <info@magenta.dk>"]
5
5
  description = "OS2mo-data-import-and-export"
6
6
  license = "MPL-2.0"
@@ -1,68 +0,0 @@
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()
@@ -1,47 +0,0 @@
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 ###
@@ -1,40 +0,0 @@
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()
@@ -1,14 +0,0 @@
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())
@@ -1,23 +0,0 @@
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,201 +0,0 @@
1
- #!/usr/bin/env python3
2
- #
3
- # This Source Code Form is subject to the terms of the Mozilla Public
4
- # License, v. 2.0. If a copy of the MPL was not distributed with this
5
- # file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
- #
7
- from datetime import date
8
- from functools import lru_cache
9
- from typing import Any
10
- from typing import Dict
11
- from typing import List
12
- from typing import Optional
13
- from typing import Type
14
-
15
- from pydantic import AnyHttpUrl
16
- from pydantic import BaseSettings
17
- from pydantic import conint
18
- from pydantic import constr
19
- from pydantic import Extra
20
- from pydantic import Field
21
- from pydantic import PositiveInt
22
- from pydantic import SecretStr
23
- from pydantic import UUID4
24
- from ra_utils.load_settings import load_settings
25
- from ra_utils.job_settings import JobSettings
26
-
27
- from .log import LogLevel
28
- from .models import JobFunction
29
-
30
-
31
- class CommonSettings(BaseSettings): # type: ignore
32
- """
33
- Settings common to both the SD importer and SD-changed-at
34
- """
35
-
36
- mora_base: AnyHttpUrl = Field("http://mo-service:5000")
37
- mox_base: AnyHttpUrl = Field("http://mo-service:5000/lora")
38
-
39
- sd_employment_field: Optional[str] = Field(default=None, regex="extension_[0-9]+")
40
- sd_global_from_date: date
41
- sd_import_run_db: str
42
- sd_import_too_deep: List[str] = []
43
- sd_institution_identifier: str
44
- sd_password: SecretStr
45
- sd_user: str
46
- sd_job_function: JobFunction
47
- sd_monthly_hourly_divide: PositiveInt
48
-
49
- # List of SD JobPositionIdentifiers which should not result in creation
50
- # of engagements
51
- sd_skip_employment_types: List[str] = []
52
-
53
- # If true, the <TelephoneNumberIdentifier> in <ContactInformation> in
54
- # <Employment> in the <Person> tag will be used to set a value that can
55
- # trigger AD-creation of the user
56
- # (see https://redmine.magenta-aps.dk/issues/56089)
57
- sd_phone_number_id_for_ad_creation: bool = False
58
- # SD can only set <TelephoneNumberIdentifier> to an integer value, hence
59
- # the value 14 is used (letters A=1 and D=4 for "AD")
60
- sd_phone_number_id_trigger: str = "14"
61
- sd_phone_number_id_for_ad_string: str = "AD-bruger fra SD"
62
-
63
- cpr_uuid_map_path: str = (
64
- "/opt/dipex/os2mo-data-import-and-export/settings/cpr_uuid_map.csv"
65
- )
66
-
67
- log_level: LogLevel = LogLevel.DEBUG
68
-
69
- job_settings: JobSettings = JobSettings()
70
-
71
-
72
- def gen_json_file_settings_func(settings_class: Type[CommonSettings]):
73
- def json_file_settings(settings: BaseSettings) -> Dict[str, Any]: # type: ignore
74
- try:
75
- json_settings = load_settings()
76
- except FileNotFoundError:
77
- return dict()
78
-
79
- # Remove the "integrations.SD_Lon." part of the key name
80
- json_settings = {
81
- key.replace("integrations.SD_Lon.", "sd_"): value
82
- for key, value in json_settings.items()
83
- }
84
-
85
- # Remove any double "sd_sd_" in the keys
86
- json_settings = {
87
- key.replace("sd_sd_", "sd_"): value for key, value in json_settings.items()
88
- }
89
-
90
- # Replace dots with underscores to be Pydantic compliant
91
- json_settings = {
92
- key.replace(".", "_"): value for key, value in json_settings.items()
93
- }
94
-
95
- # Remove settings forbidden according to the Settings model
96
- properties = settings_class.schema()["properties"].keys()
97
- json_settings = {
98
- key: value for key, value in json_settings.items() if key in properties
99
- }
100
-
101
- return json_settings
102
-
103
- return json_file_settings
104
-
105
-
106
- class SDCommonSettings(CommonSettings):
107
- class Config:
108
- extra = Extra.forbid
109
-
110
- @classmethod
111
- def customise_sources(
112
- cls,
113
- init_settings,
114
- env_settings,
115
- file_secret_settings,
116
- ):
117
- return (
118
- init_settings,
119
- env_settings,
120
- gen_json_file_settings_func(SDCommonSettings),
121
- file_secret_settings,
122
- )
123
-
124
-
125
- class ImporterSettings(CommonSettings):
126
- municipality_code: conint(ge=100, le=999) # type: ignore
127
- municipality_name: str
128
- sd_importer_create_associations: bool = True
129
- sd_importer_create_email_addresses: bool = True
130
-
131
- # Deprecated
132
- sd_importer_employment_date_as_engagement_start_date: bool = False
133
-
134
- sd_no_salary_minimum_id: Optional[int] = None
135
- sd_use_ad_integration: bool = True
136
-
137
- class Config:
138
- extra = Extra.forbid
139
-
140
- @classmethod
141
- def customise_sources(
142
- cls,
143
- init_settings,
144
- env_settings,
145
- file_secret_settings,
146
- ):
147
- return (
148
- init_settings,
149
- env_settings,
150
- gen_json_file_settings_func(ImporterSettings),
151
- file_secret_settings,
152
- )
153
-
154
-
155
- class ChangedAtSettings(CommonSettings):
156
- sd_fix_departments_root: Optional[UUID4] = None
157
- sd_no_salary_minimum_id: Optional[int] = None
158
- sd_overwrite_existing_employment_name = True
159
-
160
- # List of CRPs to either include OR exclude in the run
161
- sd_cprs: List[constr(regex="^[0-9]{10}$")] = [] # type: ignore # noqa
162
-
163
- # If true, the sd_cprs will be excluded and if false, only the
164
- # CPRs in sd_cprs will be included in the run
165
- sd_exclude_cprs_mode: bool = True
166
-
167
- sd_read_forced_uuids: bool = True
168
- sd_update_primary_engagement: bool = True
169
- sd_use_ad_integration: bool = True
170
-
171
- class Config:
172
- extra = Extra.forbid
173
-
174
- @classmethod
175
- def customise_sources(
176
- cls,
177
- init_settings,
178
- env_settings,
179
- file_secret_settings,
180
- ):
181
- return (
182
- init_settings,
183
- env_settings,
184
- gen_json_file_settings_func(ChangedAtSettings),
185
- file_secret_settings,
186
- )
187
-
188
-
189
- @lru_cache()
190
- def get_common_settings(*args, **kwargs) -> SDCommonSettings:
191
- return SDCommonSettings(*args, **kwargs)
192
-
193
-
194
- @lru_cache()
195
- def get_importer_settings(*args, **kwargs) -> ImporterSettings:
196
- return ImporterSettings(*args, **kwargs)
197
-
198
-
199
- @lru_cache()
200
- def get_changed_at_settings(*args, **kwargs) -> ChangedAtSettings:
201
- return ChangedAtSettings(*args, **kwargs)
@@ -1,181 +0,0 @@
1
- import logging
2
- import re
3
- from datetime import date
4
- from datetime import datetime
5
- from datetime import timedelta
6
- from itertools import chain
7
- from itertools import takewhile
8
- from typing import OrderedDict
9
- from typing import Union
10
- from typing import Iterator
11
- from typing import Optional
12
- from typing import Tuple
13
-
14
- from more_itertools import pairwise
15
- from more_itertools import tabulate
16
-
17
- from .log import get_logger
18
- from .sd_common import EmploymentStatus
19
-
20
- # TODO: move constants elsewhere
21
- # TODO: set back to "infinity" when MO can handle this
22
- # MO_INFINITY: str = "infinity"
23
-
24
- MO_INFINITY = None
25
- SD_INFINITY: str = "9999-12-31"
26
- DATE_REGEX_STR = "[0-9]{4}-(0[1-9]|1[0-2])-([0-2][0-9]|3[0-1])"
27
-
28
- logger = get_logger()
29
-
30
-
31
- def date_to_datetime(d: date) -> datetime:
32
- return datetime(d.year, d.month, d.day)
33
-
34
-
35
- def format_date(d: datetime | date) -> str:
36
- return d.strftime("%Y-%m-%d").zfill(10)
37
-
38
-
39
- def parse_datetime(date_str: str) -> datetime:
40
- return datetime.strptime(date_str, "%Y-%m-%d")
41
-
42
-
43
- def datetime_to_sd_date(date_time: Union[datetime, date]) -> str:
44
- return date_time.strftime("%d.%m.%Y")
45
-
46
-
47
- def _get_employment_from_date(employment: OrderedDict) -> datetime:
48
- """
49
- Get the latest date of all the dates in the payload from the SD
50
- GetEmployment endpoint (see https://redmine.magenta-aps.dk/issues/51898)
51
-
52
- Args:
53
- employment: the SD employment
54
-
55
- Returns: the maximum of all the date in the SD payload
56
-
57
- """
58
- MIN_DATE = format_date(datetime.min)
59
-
60
- employment_date = employment.get("EmploymentDate", MIN_DATE)
61
- employment_department_date = employment.get("EmploymentDepartment", dict()).get(
62
- "ActivationDate", MIN_DATE
63
- )
64
- employment_status_date = employment.get("EmploymentStatus", dict()).get(
65
- "ActivationDate", MIN_DATE
66
- )
67
- profession_date = employment.get("Profession", dict()).get(
68
- "ActivationDate", MIN_DATE
69
- )
70
- working_time_date = employment.get("WorkingTime", dict()).get(
71
- "ActivationDate", MIN_DATE
72
- )
73
-
74
- return max(
75
- parse_datetime(employment_date),
76
- parse_datetime(employment_department_date),
77
- parse_datetime(employment_status_date),
78
- parse_datetime(profession_date),
79
- parse_datetime(working_time_date),
80
- )
81
-
82
-
83
- def get_employment_datetimes(employment: OrderedDict) -> Tuple[datetime, datetime]:
84
- """
85
- Get the "from" and "to" date from the SD employment
86
-
87
- Args:
88
- employment: The SD employment
89
-
90
- Returns:
91
- Tuple containing the "from" and "to" dates.
92
- """
93
-
94
- status = EmploymentStatus(employment["EmploymentStatus"]["EmploymentStatusCode"])
95
-
96
- if status in EmploymentStatus.let_go():
97
- datetime_from = parse_datetime(employment["EmploymentDate"])
98
- termination_date = str(
99
- sd_to_mo_termination_date(employment["EmploymentStatus"]["ActivationDate"])
100
- )
101
- datetime_to = parse_datetime(termination_date)
102
- return datetime_from, datetime_to
103
-
104
- datetime_from = _get_employment_from_date(employment)
105
- datetime_to = parse_datetime(employment["EmploymentStatus"]["DeactivationDate"])
106
-
107
- return datetime_from, datetime_to
108
-
109
-
110
- # TODO: Create "MoValidity" and "SdValidity" classes based on the RA Models
111
- # "Validity" class and use these as input to the function below
112
-
113
-
114
- def sd_to_mo_termination_date(sd_date: str) -> Optional[str]:
115
- """
116
- Convert SD termination date to MO termination date.
117
-
118
- Args:
119
- sd_date: SD termination date formatted as "YYYY-MM-DD"
120
-
121
- Returns:
122
- MO termination date formatted as "YYYY-MM-DD"
123
- """
124
-
125
- assert isinstance(sd_date, str)
126
- assert re.compile(DATE_REGEX_STR).match(sd_date)
127
-
128
- if sd_date == SD_INFINITY:
129
- return MO_INFINITY
130
-
131
- return sd_date
132
-
133
-
134
- def to_midnight(dt: datetime) -> datetime:
135
- """Get previous midnight from datetime."""
136
- return dt.replace(hour=0, minute=0, second=0, microsecond=0)
137
-
138
-
139
- def is_midnight(dt: datetime) -> bool:
140
- """Check if datetime is at midnight."""
141
- return dt == to_midnight(dt)
142
-
143
-
144
- def gen_cut_dates(from_datetime: datetime, to_datetime: datetime) -> Iterator[datetime]:
145
- """Get iterator of cut-dates between from_datetime and to_datetime.
146
-
147
- Args:
148
- from_datetime: the start date
149
- to_datetime: the end date
150
-
151
- Yields:
152
- The from_datetime, then all intermediate midnight datetimes and the to_datetime.
153
- """
154
- assert from_datetime < to_datetime
155
-
156
- # Tabulate to infinite iterator of midnights starting after from_datetime
157
- def midnight_at_offset(offset: int) -> datetime:
158
- return to_midnight(from_datetime) + timedelta(days=offset)
159
-
160
- midnights = takewhile(
161
- lambda midnight: midnight < to_datetime, tabulate(midnight_at_offset, start=1)
162
- )
163
- return chain([from_datetime], midnights, [to_datetime])
164
-
165
-
166
- def gen_date_intervals(
167
- from_datetime: datetime, to_datetime: datetime
168
- ) -> Iterator[Tuple[datetime, datetime]]:
169
- """
170
- Get iterator capable of generating a sequence of datetime pairs
171
- incrementing one day at a time. The latter date in a pair is
172
- advanced by exactly one day compared to the former date in the pair.
173
-
174
- Args:
175
- from_datetime: the start date
176
- to_datetime: the end date
177
-
178
- Yields:
179
- The next date pair in the sequence of pairs
180
- """
181
- return pairwise(gen_cut_dates(from_datetime, to_datetime))
@@ -1,51 +0,0 @@
1
- from uuid import UUID
2
-
3
- from gql import gql
4
- from more_itertools import one
5
- from raclients.graph.client import GraphQLClient
6
- from sdlon.models import MOBasePerson
7
-
8
- QUERY_GET_EMPLOYEE = gql(
9
- """
10
- query GetEmployee($cpr: [CPR!]!) {
11
- employees(cpr_numbers: $cpr) {
12
- objects {
13
- current {
14
- name
15
- givenname
16
- surname
17
- uuid
18
- }
19
- }
20
- }
21
- }
22
- """
23
- )
24
-
25
-
26
- def get_employee(gql_client: GraphQLClient, cpr: str) -> MOBasePerson | None:
27
- """
28
- Get employee from MO
29
-
30
- Args:
31
- gql_client: The GraphQl client for calling MO
32
- cpr: The CPR number of the employee
33
-
34
- Returns:
35
- The MO employee or None if the employee does not exist in MO
36
- """
37
- r = gql_client.execute(QUERY_GET_EMPLOYEE, variable_values={"cpr": cpr})
38
-
39
- obj = r["employees"]["objects"]
40
- if not obj:
41
- return None
42
-
43
- employee = one(obj)["current"]
44
-
45
- return MOBasePerson(
46
- cpr=cpr,
47
- givenname=employee["givenname"],
48
- surname=employee["surname"],
49
- name=employee["name"],
50
- uuid=UUID(employee["uuid"]),
51
- )