trueppm-api 0.4.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.
- trueppm_api/__init__.py +27 -0
- trueppm_api/apps/access/__init__.py +0 -0
- trueppm_api/apps/access/apps.py +19 -0
- trueppm_api/apps/access/groups.py +518 -0
- trueppm_api/apps/access/management/__init__.py +0 -0
- trueppm_api/apps/access/management/commands/__init__.py +0 -0
- trueppm_api/apps/access/management/commands/create_admin.py +346 -0
- trueppm_api/apps/access/management/commands/migrate_locked.py +96 -0
- trueppm_api/apps/access/management/commands/revoke_api_tokens.py +483 -0
- trueppm_api/apps/access/migrations/0001_initial.py +61 -0
- trueppm_api/apps/access/migrations/0001_squashed_0012_programmembership_role_title.py +184 -0
- trueppm_api/apps/access/migrations/0002_alter_projectmembership_id.py +29 -0
- trueppm_api/apps/access/migrations/0003_projectmembership_soft_delete.py +24 -0
- trueppm_api/apps/access/migrations/0004_alter_projectmembership_role.py +34 -0
- trueppm_api/apps/access/migrations/0005_program_entity_and_membership.py +76 -0
- trueppm_api/apps/access/migrations/0006_role_ordinal_spacing.py +113 -0
- trueppm_api/apps/access/migrations/0007_projectmembership_joined_at_and_more.py +35 -0
- trueppm_api/apps/access/migrations/0008_projectmembership_source_group.py +25 -0
- trueppm_api/apps/access/migrations/0009_projectmembership_pm_proj_serverver_idx.py +20 -0
- trueppm_api/apps/access/migrations/0010_programmembership_joined_at_and_more.py +38 -0
- trueppm_api/apps/access/migrations/0011_alter_programmembership_unique_together_and_more.py +36 -0
- trueppm_api/apps/access/migrations/0012_programmembership_role_title.py +17 -0
- trueppm_api/apps/access/migrations/0013_squashed_0019_release_0_4.py +302 -0
- trueppm_api/apps/access/migrations/0013_userdefinedmentiongroup.py +82 -0
- trueppm_api/apps/access/migrations/0014_programmembership_progm_serverver_idx.py +19 -0
- trueppm_api/apps/access/migrations/0015_programuserdefinedmentiongroup.py +86 -0
- trueppm_api/apps/access/migrations/0016_externalstakeholder.py +67 -0
- trueppm_api/apps/access/migrations/0017_viewer_ordinal_one.py +143 -0
- trueppm_api/apps/access/migrations/0018_programmembership_sync_seq_and_more.py +52 -0
- trueppm_api/apps/access/migrations/0019_programmembership_reinstated_at_and_more.py +22 -0
- trueppm_api/apps/access/migrations/__init__.py +0 -0
- trueppm_api/apps/access/minter_role.py +38 -0
- trueppm_api/apps/access/models.py +588 -0
- trueppm_api/apps/access/permissions.py +3263 -0
- trueppm_api/apps/access/serializers.py +1007 -0
- trueppm_api/apps/access/services.py +878 -0
- trueppm_api/apps/access/signals.py +171 -0
- trueppm_api/apps/access/tasks.py +50 -0
- trueppm_api/apps/access/throttles.py +96 -0
- trueppm_api/apps/access/urls.py +191 -0
- trueppm_api/apps/access/views.py +1965 -0
- trueppm_api/apps/agents/__init__.py +6 -0
- trueppm_api/apps/agents/apps.py +11 -0
- trueppm_api/apps/agents/canonical.py +73 -0
- trueppm_api/apps/agents/deferred.py +108 -0
- trueppm_api/apps/agents/management/__init__.py +0 -0
- trueppm_api/apps/agents/management/commands/__init__.py +0 -0
- trueppm_api/apps/agents/management/commands/audit_prune.py +137 -0
- trueppm_api/apps/agents/management/commands/audit_verify.py +101 -0
- trueppm_api/apps/agents/middleware.py +44 -0
- trueppm_api/apps/agents/migrations/0001_initial.py +231 -0
- trueppm_api/apps/agents/migrations/0001_squashed_0003_release_0_4.py +344 -0
- trueppm_api/apps/agents/migrations/0002_agentactioncheckpoint.py +71 -0
- trueppm_api/apps/agents/migrations/0003_agentactionrefusaldetail.py +58 -0
- trueppm_api/apps/agents/migrations/__init__.py +0 -0
- trueppm_api/apps/agents/models.py +371 -0
- trueppm_api/apps/agents/refusal.py +103 -0
- trueppm_api/apps/agents/serializers.py +85 -0
- trueppm_api/apps/agents/services.py +397 -0
- trueppm_api/apps/agents/signals.py +30 -0
- trueppm_api/apps/agents/urls.py +15 -0
- trueppm_api/apps/agents/views.py +109 -0
- trueppm_api/apps/csvimport/__init__.py +12 -0
- trueppm_api/apps/csvimport/apps.py +11 -0
- trueppm_api/apps/csvimport/mapping.py +363 -0
- trueppm_api/apps/csvimport/migrations/0001_initial.py +74 -0
- trueppm_api/apps/csvimport/migrations/0001_squashed_0003_release_0_4.py +90 -0
- trueppm_api/apps/csvimport/migrations/0002_schedule_outline_batch_operations.py +37 -0
- trueppm_api/apps/csvimport/migrations/0003_csvimportrequest_date_order_and_more.py +26 -0
- trueppm_api/apps/csvimport/migrations/__init__.py +0 -0
- trueppm_api/apps/csvimport/models.py +111 -0
- trueppm_api/apps/csvimport/parser.py +1825 -0
- trueppm_api/apps/csvimport/services.py +48 -0
- trueppm_api/apps/csvimport/tasks.py +459 -0
- trueppm_api/apps/csvimport/template.py +37 -0
- trueppm_api/apps/csvimport/urls.py +50 -0
- trueppm_api/apps/csvimport/views.py +793 -0
- trueppm_api/apps/history/__init__.py +0 -0
- trueppm_api/apps/history/apps.py +12 -0
- trueppm_api/apps/history/changelog.py +359 -0
- trueppm_api/apps/history/diff_policy.py +178 -0
- trueppm_api/apps/history/serializers.py +104 -0
- trueppm_api/apps/history/signals.py +82 -0
- trueppm_api/apps/history/tasks.py +105 -0
- trueppm_api/apps/history/urls.py +38 -0
- trueppm_api/apps/history/views.py +443 -0
- trueppm_api/apps/idempotency/__init__.py +0 -0
- trueppm_api/apps/idempotency/apps.py +11 -0
- trueppm_api/apps/idempotency/migrations/0001_initial.py +71 -0
- trueppm_api/apps/idempotency/migrations/__init__.py +0 -0
- trueppm_api/apps/idempotency/mixins.py +226 -0
- trueppm_api/apps/idempotency/models.py +75 -0
- trueppm_api/apps/idempotency/tasks.py +61 -0
- trueppm_api/apps/integrations/__init__.py +13 -0
- trueppm_api/apps/integrations/apps.py +59 -0
- trueppm_api/apps/integrations/connections.py +806 -0
- trueppm_api/apps/integrations/encryption.py +92 -0
- trueppm_api/apps/integrations/external_sources.py +863 -0
- trueppm_api/apps/integrations/git_automation_services.py +231 -0
- trueppm_api/apps/integrations/git_webhook_auth.py +243 -0
- trueppm_api/apps/integrations/http.py +597 -0
- trueppm_api/apps/integrations/me_work.py +218 -0
- trueppm_api/apps/integrations/migrations/0001_initial.py +64 -0
- trueppm_api/apps/integrations/migrations/0001_squashed_0006_tasklink_description_tasklink_preview_type_and_more.py +187 -0
- trueppm_api/apps/integrations/migrations/0002_tasklink.py +67 -0
- trueppm_api/apps/integrations/migrations/0003_tasklink_tasklink_serverver_idx.py +17 -0
- trueppm_api/apps/integrations/migrations/0004_tasklink_custom_title_tasklink_labels.py +25 -0
- trueppm_api/apps/integrations/migrations/0005_boardautomation.py +56 -0
- trueppm_api/apps/integrations/migrations/0006_tasklink_description_tasklink_preview_type_and_more.py +40 -0
- trueppm_api/apps/integrations/migrations/0007_squashed_0014_release_0_4.py +225 -0
- trueppm_api/apps/integrations/migrations/0007_tasklink_created_at.py +23 -0
- trueppm_api/apps/integrations/migrations/0008_integrationcredential_config_externalworkitem.py +66 -0
- trueppm_api/apps/integrations/migrations/0009_externalsyncrequest_and_more.py +96 -0
- trueppm_api/apps/integrations/migrations/0010_externalworkitem_due_date.py +17 -0
- trueppm_api/apps/integrations/migrations/0011_tasklink_sync_seq_tasklink_tasklink_syncseq_idx.py +22 -0
- trueppm_api/apps/integrations/migrations/0012_boardautomation_last_delivery_at_and_more.py +42 -0
- trueppm_api/apps/integrations/migrations/0013_externalsyncrequest_attempt_count_and_more.py +26 -0
- trueppm_api/apps/integrations/migrations/0014_tasklink_created_by.py +27 -0
- trueppm_api/apps/integrations/migrations/__init__.py +0 -0
- trueppm_api/apps/integrations/models.py +635 -0
- trueppm_api/apps/integrations/notification_channels.py +57 -0
- trueppm_api/apps/integrations/opengraph.py +229 -0
- trueppm_api/apps/integrations/outgoing.py +201 -0
- trueppm_api/apps/integrations/providers.py +528 -0
- trueppm_api/apps/integrations/registry.py +345 -0
- trueppm_api/apps/integrations/serializers.py +453 -0
- trueppm_api/apps/integrations/services.py +171 -0
- trueppm_api/apps/integrations/tasks.py +734 -0
- trueppm_api/apps/integrations/throttles.py +165 -0
- trueppm_api/apps/integrations/urls.py +77 -0
- trueppm_api/apps/integrations/views.py +1158 -0
- trueppm_api/apps/jiraimport/__init__.py +8 -0
- trueppm_api/apps/jiraimport/apps.py +11 -0
- trueppm_api/apps/jiraimport/migrations/0001_initial.py +72 -0
- trueppm_api/apps/jiraimport/migrations/__init__.py +0 -0
- trueppm_api/apps/jiraimport/models.py +70 -0
- trueppm_api/apps/jiraimport/parser.py +350 -0
- trueppm_api/apps/jiraimport/services.py +46 -0
- trueppm_api/apps/jiraimport/tasks.py +280 -0
- trueppm_api/apps/jiraimport/urls.py +15 -0
- trueppm_api/apps/jiraimport/views.py +153 -0
- trueppm_api/apps/msproject/__init__.py +0 -0
- trueppm_api/apps/msproject/apps.py +11 -0
- trueppm_api/apps/msproject/dataclasses.py +153 -0
- trueppm_api/apps/msproject/exporter.py +551 -0
- trueppm_api/apps/msproject/extended_attributes.py +77 -0
- trueppm_api/apps/msproject/importer.py +1095 -0
- trueppm_api/apps/msproject/migrations/0001_import_request.py +77 -0
- trueppm_api/apps/msproject/migrations/0001_squashed_0002_importrequest_creates_project.py +80 -0
- trueppm_api/apps/msproject/migrations/0002_importrequest_creates_project.py +15 -0
- trueppm_api/apps/msproject/migrations/__init__.py +0 -0
- trueppm_api/apps/msproject/models.py +81 -0
- trueppm_api/apps/msproject/parser.py +1276 -0
- trueppm_api/apps/msproject/serializers.py +136 -0
- trueppm_api/apps/msproject/services.py +58 -0
- trueppm_api/apps/msproject/tasks.py +439 -0
- trueppm_api/apps/msproject/urls.py +39 -0
- trueppm_api/apps/msproject/views.py +531 -0
- trueppm_api/apps/notifications/__init__.py +7 -0
- trueppm_api/apps/notifications/apps.py +15 -0
- trueppm_api/apps/notifications/backfill.py +79 -0
- trueppm_api/apps/notifications/categories.py +112 -0
- trueppm_api/apps/notifications/delivery_limits.py +258 -0
- trueppm_api/apps/notifications/digests.py +462 -0
- trueppm_api/apps/notifications/email_backend.py +350 -0
- trueppm_api/apps/notifications/email_health.py +128 -0
- trueppm_api/apps/notifications/migrations/0001_initial.py +207 -0
- trueppm_api/apps/notifications/migrations/0001_squashed_0006_notification_task.py +299 -0
- trueppm_api/apps/notifications/migrations/0002_project_notification_preference.py +67 -0
- trueppm_api/apps/notifications/migrations/0003_projectnotificationpreference_paused.py +17 -0
- trueppm_api/apps/notifications/migrations/0004_clean_unknown_matrix_keys.py +30 -0
- trueppm_api/apps/notifications/migrations/0005_notification_body_notification_event_type_and_more.py +27 -0
- trueppm_api/apps/notifications/migrations/0006_notification_task.py +25 -0
- trueppm_api/apps/notifications/migrations/0007_squashed_0011_release_0_4.py +204 -0
- trueppm_api/apps/notifications/migrations/0007_workspaceemailsettings.py +80 -0
- trueppm_api/apps/notifications/migrations/0008_notification_snoozed_until.py +17 -0
- trueppm_api/apps/notifications/migrations/0009_usernotificationsettings.py +43 -0
- trueppm_api/apps/notifications/migrations/0010_projectnotificationpreference_schema_version.py +20 -0
- trueppm_api/apps/notifications/migrations/0011_usernotificationsettings_digest_hour_and_more.py +96 -0
- trueppm_api/apps/notifications/migrations/__init__.py +0 -0
- trueppm_api/apps/notifications/models.py +1148 -0
- trueppm_api/apps/notifications/receivers.py +155 -0
- trueppm_api/apps/notifications/schema_migrations.py +56 -0
- trueppm_api/apps/notifications/serializers.py +1094 -0
- trueppm_api/apps/notifications/services.py +1489 -0
- trueppm_api/apps/notifications/tasks.py +762 -0
- trueppm_api/apps/notifications/throttles.py +98 -0
- trueppm_api/apps/notifications/urls.py +97 -0
- trueppm_api/apps/notifications/views.py +919 -0
- trueppm_api/apps/observability/__init__.py +0 -0
- trueppm_api/apps/observability/apps.py +31 -0
- trueppm_api/apps/observability/logging.py +213 -0
- trueppm_api/apps/observability/migrations/0001_initial.py +35 -0
- trueppm_api/apps/observability/migrations/0001_squashed_0003_alter_purgerun_trigger.py +154 -0
- trueppm_api/apps/observability/migrations/0002_purgerun_retentionpolicy_retentionschedule.py +131 -0
- trueppm_api/apps/observability/migrations/0003_alter_purgerun_trigger.py +21 -0
- trueppm_api/apps/observability/migrations/0004_alter_retentionpolicy_key.py +28 -0
- trueppm_api/apps/observability/migrations/__init__.py +0 -0
- trueppm_api/apps/observability/models.py +141 -0
- trueppm_api/apps/observability/otel/__init__.py +45 -0
- trueppm_api/apps/observability/otel/attributes.py +247 -0
- trueppm_api/apps/observability/otel/export_health.py +533 -0
- trueppm_api/apps/observability/otel/instrumentation.py +351 -0
- trueppm_api/apps/observability/otel/metrics.py +566 -0
- trueppm_api/apps/observability/otel/provider.py +511 -0
- trueppm_api/apps/observability/otel/request_attributes.py +204 -0
- trueppm_api/apps/observability/purge_registry.py +124 -0
- trueppm_api/apps/observability/retention.py +139 -0
- trueppm_api/apps/observability/selectors.py +993 -0
- trueppm_api/apps/observability/serializers.py +142 -0
- trueppm_api/apps/observability/services.py +407 -0
- trueppm_api/apps/observability/tasks.py +266 -0
- trueppm_api/apps/observability/urls.py +27 -0
- trueppm_api/apps/observability/views.py +537 -0
- trueppm_api/apps/profiles/__init__.py +0 -0
- trueppm_api/apps/profiles/apps.py +15 -0
- trueppm_api/apps/profiles/constants.py +54 -0
- trueppm_api/apps/profiles/migrations/0001_initial.py +55 -0
- trueppm_api/apps/profiles/migrations/0001_squashed_0004_userprofile_role_context.py +125 -0
- trueppm_api/apps/profiles/migrations/0002_userprofile_hidden_views.py +17 -0
- trueppm_api/apps/profiles/migrations/0003_projectvisit.py +63 -0
- trueppm_api/apps/profiles/migrations/0004_userprofile_role_context.py +26 -0
- trueppm_api/apps/profiles/migrations/0005_squashed_0009_release_0_4.py +128 -0
- trueppm_api/apps/profiles/migrations/0005_userprofile_schedule_in_deliver.py +20 -0
- trueppm_api/apps/profiles/migrations/0006_userprofile_date_format_userprofile_timezone.py +36 -0
- trueppm_api/apps/profiles/migrations/0007_userpin.py +91 -0
- trueppm_api/apps/profiles/migrations/0008_remove_userprofile_schedule_in_deliver.py +71 -0
- trueppm_api/apps/profiles/migrations/0009_auth_user_email_upper_idx.py +81 -0
- trueppm_api/apps/profiles/migrations/__init__.py +0 -0
- trueppm_api/apps/profiles/models.py +276 -0
- trueppm_api/apps/profiles/serializers.py +199 -0
- trueppm_api/apps/profiles/services.py +541 -0
- trueppm_api/apps/profiles/views.py +124 -0
- trueppm_api/apps/projects/__init__.py +0 -0
- trueppm_api/apps/projects/actual_date_rules.py +163 -0
- trueppm_api/apps/projects/amend.py +133 -0
- trueppm_api/apps/projects/apps.py +38 -0
- trueppm_api/apps/projects/asset_feed.py +459 -0
- trueppm_api/apps/projects/asset_views.py +317 -0
- trueppm_api/apps/projects/attachment_policy.py +278 -0
- trueppm_api/apps/projects/authentication.py +458 -0
- trueppm_api/apps/projects/backfill.py +459 -0
- trueppm_api/apps/projects/backlog_services.py +324 -0
- trueppm_api/apps/projects/backlog_views.py +302 -0
- trueppm_api/apps/projects/batch_operation_views.py +264 -0
- trueppm_api/apps/projects/blocker_services.py +510 -0
- trueppm_api/apps/projects/board_activity.py +462 -0
- trueppm_api/apps/projects/board_activity_views.py +186 -0
- trueppm_api/apps/projects/board_lanes.py +134 -0
- trueppm_api/apps/projects/bulk_settings.py +194 -0
- trueppm_api/apps/projects/bundled_templates.py +215 -0
- trueppm_api/apps/projects/calendar_settings.py +180 -0
- trueppm_api/apps/projects/ceremony_views.py +244 -0
- trueppm_api/apps/projects/commit_moment.py +212 -0
- trueppm_api/apps/projects/config_notice.py +1330 -0
- trueppm_api/apps/projects/custom_field_values.py +266 -0
- trueppm_api/apps/projects/decisions_services.py +132 -0
- trueppm_api/apps/projects/decisions_views.py +97 -0
- trueppm_api/apps/projects/estimation_scale.py +126 -0
- trueppm_api/apps/projects/export_bundle.py +423 -0
- trueppm_api/apps/projects/fixtures/seeds/atlas-platform-launch.json +4278 -0
- trueppm_api/apps/projects/fixtures/seeds/aurora-mobile-app.json +2001 -0
- trueppm_api/apps/projects/fixtures/seeds/bayside-civic-center.json +1827 -0
- trueppm_api/apps/projects/fixtures/seeds/ga-launch.json +1909 -0
- trueppm_api/apps/projects/fixtures/seeds/helios-crm-replacement.json +1410 -0
- trueppm_api/apps/projects/guardrail_policy_source.py +269 -0
- trueppm_api/apps/projects/inbound_sync.py +555 -0
- trueppm_api/apps/projects/iteration_label.py +85 -0
- trueppm_api/apps/projects/key_views.py +468 -0
- trueppm_api/apps/projects/keys.py +205 -0
- trueppm_api/apps/projects/lifecycle.py +191 -0
- trueppm_api/apps/projects/management/__init__.py +0 -0
- trueppm_api/apps/projects/management/commands/__init__.py +0 -0
- trueppm_api/apps/projects/management/commands/backfill_in_progress_status.py +92 -0
- trueppm_api/apps/projects/management/commands/create_demo_share_link.py +368 -0
- trueppm_api/apps/projects/management/commands/export_program.py +50 -0
- trueppm_api/apps/projects/management/commands/import_seed.py +165 -0
- trueppm_api/apps/projects/management/commands/load_sample_project.py +514 -0
- trueppm_api/apps/projects/management/commands/seed_capacity.py +406 -0
- trueppm_api/apps/projects/management/commands/seed_integration_fixtures.py +192 -0
- trueppm_api/apps/projects/management/commands/shift_sample_dates.py +120 -0
- trueppm_api/apps/projects/mcp_settings.py +305 -0
- trueppm_api/apps/projects/methodology.py +178 -0
- trueppm_api/apps/projects/migration_helpers.py +75 -0
- trueppm_api/apps/projects/migrations/0001_initial.py +208 -0
- trueppm_api/apps/projects/migrations/0001_squashed_0094_project_decisions_policy.py +5659 -0
- trueppm_api/apps/projects/migrations/0002_alter_uuid_pk_serialize_false.py +57 -0
- trueppm_api/apps/projects/migrations/0003_rename_task_project_index.py +25 -0
- trueppm_api/apps/projects/migrations/0004_soft_delete_and_dependency_versioned.py +70 -0
- trueppm_api/apps/projects/migrations/0005_task_assignee.py +33 -0
- trueppm_api/apps/projects/migrations/0006_task_utilization_index.py +31 -0
- trueppm_api/apps/projects/migrations/0007_task_is_milestone.py +28 -0
- trueppm_api/apps/projects/migrations/0008_baseline.py +119 -0
- trueppm_api/apps/projects/migrations/0009_historicaldependency_historicalproject_and_more.py +210 -0
- trueppm_api/apps/projects/migrations/0010_risk.py +229 -0
- trueppm_api/apps/projects/migrations/0011_task_status.py +27 -0
- trueppm_api/apps/projects/migrations/0012_task_status.py +27 -0
- trueppm_api/apps/projects/migrations/0013_task_planned_start.py +24 -0
- trueppm_api/apps/projects/migrations/0014_short_hex_ids.py +74 -0
- trueppm_api/apps/projects/migrations/0015_backfill_short_ids.py +48 -0
- trueppm_api/apps/projects/migrations/0016_task_actual_dates.py +42 -0
- trueppm_api/apps/projects/migrations/0017_boardcolumnconfig.py +43 -0
- trueppm_api/apps/projects/migrations/0018_estimation_governance.py +62 -0
- trueppm_api/apps/projects/migrations/0019_backfill_wbs_paths.py +28 -0
- trueppm_api/apps/projects/migrations/0020_task_status_5col.py +65 -0
- trueppm_api/apps/projects/migrations/0021_boardsavedview.py +64 -0
- trueppm_api/apps/projects/migrations/0022_task_status_changed_at_priority_rank.py +35 -0
- trueppm_api/apps/projects/migrations/0023_risk_framework_fields.py +96 -0
- trueppm_api/apps/projects/migrations/0024_riskcomment.py +52 -0
- trueppm_api/apps/projects/migrations/0025_sprint.py +352 -0
- trueppm_api/apps/projects/migrations/0026_project_methodology.py +30 -0
- trueppm_api/apps/projects/migrations/0027_sprint_retro.py +89 -0
- trueppm_api/apps/projects/migrations/0028_normalize_notes_field.py +42 -0
- trueppm_api/apps/projects/migrations/0029_complete_implies_full_progress.py +38 -0
- trueppm_api/apps/projects/migrations/0030_review_implies_full_progress.py +37 -0
- trueppm_api/apps/projects/migrations/0031_task_remaining_points.py +22 -0
- trueppm_api/apps/projects/migrations/0032_task_is_subtask_and_sprint_scope_change.py +90 -0
- trueppm_api/apps/projects/migrations/0033_task_my_work_index.py +38 -0
- trueppm_api/apps/projects/migrations/0034_inbound_task_sync.py +313 -0
- trueppm_api/apps/projects/migrations/0035_retro_versioned_and_suggested_assignee.py +173 -0
- trueppm_api/apps/projects/migrations/0036_program_entity_and_membership.py +157 -0
- trueppm_api/apps/projects/migrations/0037_sprint_capacity_points.py +20 -0
- trueppm_api/apps/projects/migrations/0038_taskcomment_commentreaction_commentacknowledgement_and_more.py +233 -0
- trueppm_api/apps/projects/migrations/0039_apitoken_and_more.py +88 -0
- trueppm_api/apps/projects/migrations/0040_program_general_fields.py +119 -0
- trueppm_api/apps/projects/migrations/0041_ceremony_template_and_phase_gate_config.py +210 -0
- trueppm_api/apps/projects/migrations/0041_project_general_fields.py +106 -0
- trueppm_api/apps/projects/migrations/0042_merge_20260522_0410.py +12 -0
- trueppm_api/apps/projects/migrations/0042_program_rollup_config.py +95 -0
- trueppm_api/apps/projects/migrations/0042_workflow_color_and_custom_fields.py +94 -0
- trueppm_api/apps/projects/migrations/0043_merge_20260522_1118.py +10 -0
- trueppm_api/apps/projects/migrations/0044_merge_20260522_rollup.py +10 -0
- trueppm_api/apps/projects/migrations/0044_project_archive_program_close.py +119 -0
- trueppm_api/apps/projects/migrations/0045_program_risk_policy.py +78 -0
- trueppm_api/apps/projects/migrations/0046_merge_20260523_2248.py +12 -0
- trueppm_api/apps/projects/migrations/0047_apitokenauditentry_program_and_more.py +55 -0
- trueppm_api/apps/projects/migrations/0048_historicalprogram_color_program_color.py +32 -0
- trueppm_api/apps/projects/migrations/0049_backlog_item.py +112 -0
- trueppm_api/apps/projects/migrations/0050_backlog_item_trgm_search.py +26 -0
- trueppm_api/apps/projects/migrations/0051_alter_calendar_working_days_alter_dependency_lag_and_more.py +144 -0
- trueppm_api/apps/projects/migrations/0052_recurring_tasks.py +278 -0
- trueppm_api/apps/projects/migrations/0053_dependency_dep_pred_serverver_idx_and_more.py +56 -0
- trueppm_api/apps/projects/migrations/0054_sprintscopechange_goal_impact_and_more.py +117 -0
- trueppm_api/apps/projects/migrations/0055_historicaltask_sprint_pending_and_more.py +51 -0
- trueppm_api/apps/projects/migrations/0056_historicalproject_prioritization_model_and_more.py +276 -0
- trueppm_api/apps/projects/migrations/0057_historicalsprint_binding_committed_snapshot_and_more.py +58 -0
- trueppm_api/apps/projects/migrations/0058_historicaltask_delivery_mode_and_more.py +72 -0
- trueppm_api/apps/projects/migrations/0059_forecastsnapshot.py +80 -0
- trueppm_api/apps/projects/migrations/0060_historicalprojectsignalprivacypolicy_and_more.py +90 -0
- trueppm_api/apps/projects/migrations/0061_baselinetask_story_points.py +17 -0
- trueppm_api/apps/projects/migrations/0062_project_is_sample.py +22 -0
- trueppm_api/apps/projects/migrations/0063_historicalsprint_wip_limit_sprint_wip_limit.py +22 -0
- trueppm_api/apps/projects/migrations/0064_sprinttaskoutcome.py +97 -0
- trueppm_api/apps/projects/migrations/0065_historicalsprint_goal_outcome_sprint_goal_outcome.py +32 -0
- trueppm_api/apps/projects/migrations/0066_historicalproject_lead_project_lead.py +38 -0
- trueppm_api/apps/projects/migrations/0067_sprint_exclude_from_velocity.py +22 -0
- trueppm_api/apps/projects/migrations/0068_project_recalculated_at.py +23 -0
- trueppm_api/apps/projects/migrations/0069_iteration_label.py +22 -0
- trueppm_api/apps/projects/migrations/0070_historicalprogram_iteration_label_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0071_backfill_iteration_label_inherit.py +35 -0
- trueppm_api/apps/projects/migrations/0072_pulseresponse_retroboarditem.py +129 -0
- trueppm_api/apps/projects/migrations/0073_sprinttaskoutcome_demo_ready.py +17 -0
- trueppm_api/apps/projects/migrations/0074_historicaltask_blocked_reason_task_blocked_reason.py +30 -0
- trueppm_api/apps/projects/migrations/0075_risk_decimal_short_id.py +42 -0
- trueppm_api/apps/projects/migrations/0076_sprinttaskoutcome_review_polish.py +45 -0
- trueppm_api/apps/projects/migrations/0077_task_blocker_fields.py +111 -0
- trueppm_api/apps/projects/migrations/0078_alter_risktask_unique_together_and_more.py +22 -0
- trueppm_api/apps/projects/migrations/0079_historicalproject_status_date_project_status_date.py +22 -0
- trueppm_api/apps/projects/migrations/0080_alter_historicaltask_type_alter_task_type.py +46 -0
- trueppm_api/apps/projects/migrations/0081_historicalprogram_allow_guests_and_more.py +52 -0
- trueppm_api/apps/projects/migrations/0082_project_last_sync_version.py +90 -0
- trueppm_api/apps/projects/migrations/0083_historicalprogram_mc_history_attribution_audience_and_more.py +108 -0
- trueppm_api/apps/projects/migrations/0084_tasknote.py +71 -0
- trueppm_api/apps/projects/migrations/0085_sprint_ix_sprint_velocity.py +33 -0
- trueppm_api/apps/projects/migrations/0086_board_card_search_trgm.py +33 -0
- trueppm_api/apps/projects/migrations/0087_historicalprogram_task_duration_change_percent_policy_and_more.py +155 -0
- trueppm_api/apps/projects/migrations/0088_historicalprogram_allowed_attachment_types_and_more.py +61 -0
- trueppm_api/apps/projects/migrations/0089_signalceilingraiseproposal_signalceilingraisevote_and_more.py +157 -0
- trueppm_api/apps/projects/migrations/0090_historicaltask_proj_histdate_index.py +59 -0
- trueppm_api/apps/projects/migrations/0091_project_board_cadence.py +39 -0
- trueppm_api/apps/projects/migrations/0092_program_target_date.py +22 -0
- trueppm_api/apps/projects/migrations/0093_cross_project_dependency_consent.py +58 -0
- trueppm_api/apps/projects/migrations/0094_project_decisions_policy.py +90 -0
- trueppm_api/apps/projects/migrations/0095_poker_session_vote.py +127 -0
- trueppm_api/apps/projects/migrations/0095_squashed_0097_release_0_3.py +225 -0
- trueppm_api/apps/projects/migrations/0096_crossprojectslipconflict.py +91 -0
- trueppm_api/apps/projects/migrations/0097_backlogitem_backlogitem_tags_gin_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0098_historicalproject_show_baselines_and_more.py +52 -0
- trueppm_api/apps/projects/migrations/0099_apitoken_scopes.py +48 -0
- trueppm_api/apps/projects/migrations/0100_task_dep_serverver_idx_concurrent.py +75 -0
- trueppm_api/apps/projects/migrations/0101_dependency_deleted_at_task_deleted_at.py +22 -0
- trueppm_api/apps/projects/migrations/0102_project_deleted_at_project_proj_isdel_deletedat_idx.py +25 -0
- trueppm_api/apps/projects/migrations/0103_taskdurationchangeevent_task_dur_evt_sprint_idx.py +18 -0
- trueppm_api/apps/projects/migrations/0104_historicalproject_stale_task_threshold_days_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0104_trash_restore_1113.py +38 -0
- trueppm_api/apps/projects/migrations/0105_historical_changelog_indexes.py +76 -0
- trueppm_api/apps/projects/migrations/0106_boardsavedview_schema_version.py +20 -0
- trueppm_api/apps/projects/migrations/0106_squashed_0158_release_0_4.py +2357 -0
- trueppm_api/apps/projects/migrations/0107_task_activity_event.py +70 -0
- trueppm_api/apps/projects/migrations/0108_remove_apitoken_api_token_scope_xor_and_more.py +117 -0
- trueppm_api/apps/projects/migrations/0109_projectexportjob.py +82 -0
- trueppm_api/apps/projects/migrations/0110_sharelink.py +123 -0
- trueppm_api/apps/projects/migrations/0111_projectcalendarlayer.py +67 -0
- trueppm_api/apps/projects/migrations/0112_sharelink_expires_at_alter_sharelink_content_kind.py +31 -0
- trueppm_api/apps/projects/migrations/0113_alter_historicaltask_percent_complete_and_more.py +35 -0
- trueppm_api/apps/projects/migrations/0114_historicalproject_default_member_role_and_more.py +28 -0
- trueppm_api/apps/projects/migrations/0115_historicalproject_end_date_shift_threshold_days_and_more.py +22 -0
- trueppm_api/apps/projects/migrations/0116_alter_taskactivityevent_event_type.py +28 -0
- trueppm_api/apps/projects/migrations/0117_label_tasklabel_label_tasks_and_more.py +126 -0
- trueppm_api/apps/projects/migrations/0118_programexportjob.py +82 -0
- trueppm_api/apps/projects/migrations/0119_historicalprogram_calendar_program_calendar.py +36 -0
- trueppm_api/apps/projects/migrations/0120_alter_backlogitem_item_type.py +29 -0
- trueppm_api/apps/projects/migrations/0121_task_three_point_estimate_ordered.py +64 -0
- trueppm_api/apps/projects/migrations/0122_task_relation.py +173 -0
- trueppm_api/apps/projects/migrations/0123_remove_historicalproject_agile_features_and_more.py +20 -0
- trueppm_api/apps/projects/migrations/0124_dependency_is_driving.py +17 -0
- trueppm_api/apps/projects/migrations/0125_historicalprogram_estimation_scale_and_more.py +68 -0
- trueppm_api/apps/projects/migrations/0126_projectcustomfield_show_on_card_taskcustomfieldvalue.py +80 -0
- trueppm_api/apps/projects/migrations/0127_historicalprogram_mcp_enabled_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0128_acceptancecriterion_sync_seq_apitoken_sync_seq_and_more.py +192 -0
- trueppm_api/apps/projects/migrations/0129_sharelink_show_milestone_dates.py +20 -0
- trueppm_api/apps/projects/migrations/0130_programimportjob.py +85 -0
- trueppm_api/apps/projects/migrations/0131_historicalprogram_sprint_picker_ready_only_default_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0132_task_scheduled_start.py +17 -0
- trueppm_api/apps/projects/migrations/0133_project_status_date_floor_armed_at.py +17 -0
- trueppm_api/apps/projects/migrations/0134_task_edited_at_task_seeded_at_task_source_id_and_more.py +65 -0
- trueppm_api/apps/projects/migrations/0135_projecttemplate_templateapplication_and_more.py +175 -0
- trueppm_api/apps/projects/migrations/0136_schedule_outline_batch_operations.py +118 -0
- trueppm_api/apps/projects/migrations/0137_collapse_dual_scope_api_tokens.py +54 -0
- trueppm_api/apps/projects/migrations/0138_apitokenauditentry_api_token_audit_owner_idx.py +18 -0
- trueppm_api/apps/projects/migrations/0139_historicaltask_duration_unit_task_duration_unit.py +32 -0
- trueppm_api/apps/projects/migrations/0140_historicaltask_auto_container_and_more.py +113 -0
- trueppm_api/apps/projects/migrations/0141_historicalproject_draft_started_at_and_more.py +44 -0
- trueppm_api/apps/projects/migrations/0142_baseline_calendar_hours_per_day_and_more.py +31 -0
- trueppm_api/apps/projects/migrations/0143_sprintcloserequest_failure_reason_and_more.py +42 -0
- trueppm_api/apps/projects/migrations/0144_projecttemplate_source_project_and_more.py +35 -0
- trueppm_api/apps/projects/migrations/0145_seed_bundled_templates.py +65 -0
- trueppm_api/apps/projects/migrations/0146_historicaltask_board_lane_task_board_lane.py +32 -0
- trueppm_api/apps/projects/migrations/0147_structuraloperation.py +128 -0
- trueppm_api/apps/projects/migrations/0148_task_unique_task_wbs_path_per_project_live.py +76 -0
- trueppm_api/apps/projects/migrations/0149_drop_workshops_tables.py +42 -0
- trueppm_api/apps/projects/migrations/0150_clear_uncommitted_cpm_output.py +130 -0
- trueppm_api/apps/projects/migrations/0151_config_notice_request.py +70 -0
- trueppm_api/apps/projects/migrations/0152_aggregate_task_wbs_name_idx.py +20 -0
- trueppm_api/apps/projects/migrations/0153_program_sample_anchor_date.py +22 -0
- trueppm_api/apps/projects/migrations/0154_object_keys.py +184 -0
- trueppm_api/apps/projects/migrations/0155_task_milestone_at_day_end.py +20 -0
- trueppm_api/apps/projects/migrations/0156_program_import_job_replaced_project_ids.py +17 -0
- trueppm_api/apps/projects/migrations/0157_forecastsnapshot_cpm_finish_at_day_start.py +17 -0
- trueppm_api/apps/projects/migrations/0158_baselinetask_finish_at_day_start.py +17 -0
- trueppm_api/apps/projects/migrations/__init__.py +0 -0
- trueppm_api/apps/projects/models.py +9209 -0
- trueppm_api/apps/projects/poker_services.py +154 -0
- trueppm_api/apps/projects/poker_views.py +398 -0
- trueppm_api/apps/projects/product_backlog_services.py +450 -0
- trueppm_api/apps/projects/program_label_services.py +94 -0
- trueppm_api/apps/projects/program_label_views.py +189 -0
- trueppm_api/apps/projects/program_rollup.py +903 -0
- trueppm_api/apps/projects/program_schedule.py +767 -0
- trueppm_api/apps/projects/program_views.py +3445 -0
- trueppm_api/apps/projects/project_templates.py +422 -0
- trueppm_api/apps/projects/receivers.py +234 -0
- trueppm_api/apps/projects/refusal_codes.py +140 -0
- trueppm_api/apps/projects/reorder_services.py +145 -0
- trueppm_api/apps/projects/restructure_hooks.py +54 -0
- trueppm_api/apps/projects/retro_board_services.py +368 -0
- trueppm_api/apps/projects/retro_services.py +285 -0
- trueppm_api/apps/projects/risk_import.py +396 -0
- trueppm_api/apps/projects/row_identity.py +113 -0
- trueppm_api/apps/projects/schema_migrations.py +228 -0
- trueppm_api/apps/projects/schemas/seed_v1.json +492 -0
- trueppm_api/apps/projects/schemas/seed_v2.json +891 -0
- trueppm_api/apps/projects/seed/__init__.py +61 -0
- trueppm_api/apps/projects/seed/demo_landing_overlay.py +532 -0
- trueppm_api/apps/projects/seed/exporter.py +1717 -0
- trueppm_api/apps/projects/seed/forecast_backfill.py +247 -0
- trueppm_api/apps/projects/seed/importer.py +2764 -0
- trueppm_api/apps/projects/seed/reanchor.py +551 -0
- trueppm_api/apps/projects/seed/reldates.py +126 -0
- trueppm_api/apps/projects/seed/replace.py +128 -0
- trueppm_api/apps/projects/seed/replay.py +1695 -0
- trueppm_api/apps/projects/seed/replay_ctx.py +41 -0
- trueppm_api/apps/projects/seed/samples.py +427 -0
- trueppm_api/apps/projects/seed/validation.py +1169 -0
- trueppm_api/apps/projects/serializers.py +12904 -0
- trueppm_api/apps/projects/services.py +7525 -0
- trueppm_api/apps/projects/share_serializers.py +142 -0
- trueppm_api/apps/projects/share_services.py +373 -0
- trueppm_api/apps/projects/share_views.py +395 -0
- trueppm_api/apps/projects/sharing_settings.py +187 -0
- trueppm_api/apps/projects/signal_privacy_services.py +910 -0
- trueppm_api/apps/projects/signal_privacy_views.py +485 -0
- trueppm_api/apps/projects/signals.py +132 -0
- trueppm_api/apps/projects/slip_conflict.py +288 -0
- trueppm_api/apps/projects/sprint_cadence.py +453 -0
- trueppm_api/apps/projects/sprint_picker_settings.py +132 -0
- trueppm_api/apps/projects/standup.py +304 -0
- trueppm_api/apps/projects/standup_views.py +99 -0
- trueppm_api/apps/projects/structural_operation_services.py +727 -0
- trueppm_api/apps/projects/structural_operation_views.py +311 -0
- trueppm_api/apps/projects/surface_visibility.py +126 -0
- trueppm_api/apps/projects/task_batch_services.py +379 -0
- trueppm_api/apps/projects/task_bulk.py +1244 -0
- trueppm_api/apps/projects/task_classification.py +561 -0
- trueppm_api/apps/projects/task_classification_defaults.py +95 -0
- trueppm_api/apps/projects/task_duration_settings.py +142 -0
- trueppm_api/apps/projects/task_grouping.py +754 -0
- trueppm_api/apps/projects/tasks.py +1979 -0
- trueppm_api/apps/projects/template_divergence.py +168 -0
- trueppm_api/apps/projects/template_services.py +160 -0
- trueppm_api/apps/projects/template_tasks.py +261 -0
- trueppm_api/apps/projects/template_views.py +829 -0
- trueppm_api/apps/projects/throttles.py +311 -0
- trueppm_api/apps/projects/urls.py +1016 -0
- trueppm_api/apps/projects/utilization.py +909 -0
- trueppm_api/apps/projects/views.py +21225 -0
- trueppm_api/apps/projects/wbs_paths.py +119 -0
- trueppm_api/apps/resources/__init__.py +0 -0
- trueppm_api/apps/resources/apps.py +8 -0
- trueppm_api/apps/resources/capacity.py +121 -0
- trueppm_api/apps/resources/migrations/0001_initial.py +68 -0
- trueppm_api/apps/resources/migrations/0001_squashed_0013_alter_projectresource_unique_together_and_more.py +281 -0
- trueppm_api/apps/resources/migrations/0002_alter_uuid_pk_serialize_false.py +36 -0
- trueppm_api/apps/resources/migrations/0003_resource_soft_delete.py +30 -0
- trueppm_api/apps/resources/migrations/0004_add_taskresource_resource_index.py +25 -0
- trueppm_api/apps/resources/migrations/0005_resource_job_role.py +20 -0
- trueppm_api/apps/resources/migrations/0006_skill.py +34 -0
- trueppm_api/apps/resources/migrations/0007_resource_skill.py +63 -0
- trueppm_api/apps/resources/migrations/0008_project_resource.py +63 -0
- trueppm_api/apps/resources/migrations/0009_task_skill_requirement.py +60 -0
- trueppm_api/apps/resources/migrations/0010_alter_resourceskill_options_and_more.py +20 -0
- trueppm_api/apps/resources/migrations/0011_alter_projectresource_notes.py +17 -0
- trueppm_api/apps/resources/migrations/0012_add_resource_user_fk.py +26 -0
- trueppm_api/apps/resources/migrations/0013_alter_projectresource_unique_together_and_more.py +53 -0
- trueppm_api/apps/resources/migrations/0014_projectresource_sync_seq_resource_sync_seq_and_more.py +37 -0
- trueppm_api/apps/resources/migrations/0014_squashed_0015_release_0_4.py +47 -0
- trueppm_api/apps/resources/migrations/0015_projectresource_deactivated_with_resource.py +17 -0
- trueppm_api/apps/resources/migrations/__init__.py +0 -0
- trueppm_api/apps/resources/models.py +298 -0
- trueppm_api/apps/resources/serializers.py +426 -0
- trueppm_api/apps/resources/services.py +465 -0
- trueppm_api/apps/resources/urls.py +28 -0
- trueppm_api/apps/resources/views.py +1752 -0
- trueppm_api/apps/scheduling/__init__.py +0 -0
- trueppm_api/apps/scheduling/apps.py +153 -0
- trueppm_api/apps/scheduling/calendars.py +144 -0
- trueppm_api/apps/scheduling/deadletter.py +91 -0
- trueppm_api/apps/scheduling/finish_reading.py +198 -0
- trueppm_api/apps/scheduling/forecast_history_settings.py +215 -0
- trueppm_api/apps/scheduling/forecast_staleness.py +313 -0
- trueppm_api/apps/scheduling/graph_guard.py +263 -0
- trueppm_api/apps/scheduling/management/__init__.py +0 -0
- trueppm_api/apps/scheduling/management/commands/__init__.py +0 -0
- trueppm_api/apps/scheduling/management/commands/prune_forecast_snapshots.py +53 -0
- trueppm_api/apps/scheduling/mc_admission.py +181 -0
- trueppm_api/apps/scheduling/migrations/0001_failed_task.py +62 -0
- trueppm_api/apps/scheduling/migrations/0001_squashed_0007_projectforecastsnapshot.py +309 -0
- trueppm_api/apps/scheduling/migrations/0002_schedulerequest.py +78 -0
- trueppm_api/apps/scheduling/migrations/0003_add_schedule_request_reason.py +27 -0
- trueppm_api/apps/scheduling/migrations/0004_velocity_suggestion.py +94 -0
- trueppm_api/apps/scheduling/migrations/0005_montecarlorun.py +61 -0
- trueppm_api/apps/scheduling/migrations/0006_montecarlorun_distribution.py +17 -0
- trueppm_api/apps/scheduling/migrations/0007_projectforecastsnapshot.py +65 -0
- trueppm_api/apps/scheduling/migrations/0008_alter_schedulerequest_reason.py +28 -0
- trueppm_api/apps/scheduling/migrations/0008_folded_schedulerequest_reason.py +34 -0
- trueppm_api/apps/scheduling/migrations/0009_alter_schedulerequest_reason.py +29 -0
- trueppm_api/apps/scheduling/migrations/0010_failedtask_resolution_note_failedtask_resolved_at_and_more.py +43 -0
- trueppm_api/apps/scheduling/migrations/0010_squashed_0016_release_0_4.py +106 -0
- trueppm_api/apps/scheduling/migrations/0011_failedtask_project.py +26 -0
- trueppm_api/apps/scheduling/migrations/0012_montecarlorun_diagnostic.py +17 -0
- trueppm_api/apps/scheduling/migrations/0013_montecarlorun_status_date.py +17 -0
- trueppm_api/apps/scheduling/migrations/0014_montecarlorun_plan_version.py +17 -0
- trueppm_api/apps/scheduling/migrations/0015_projectforecastsnapshot_cpm_finish_at_day_start.py +17 -0
- trueppm_api/apps/scheduling/migrations/0016_montecarlorun_finish_readings.py +32 -0
- trueppm_api/apps/scheduling/migrations/__init__.py +0 -0
- trueppm_api/apps/scheduling/models.py +542 -0
- trueppm_api/apps/scheduling/receivers.py +160 -0
- trueppm_api/apps/scheduling/risk_premium.py +334 -0
- trueppm_api/apps/scheduling/serializers.py +723 -0
- trueppm_api/apps/scheduling/services.py +1251 -0
- trueppm_api/apps/scheduling/signals.py +56 -0
- trueppm_api/apps/scheduling/tasks.py +2248 -0
- trueppm_api/apps/scheduling/telemetry.py +80 -0
- trueppm_api/apps/scheduling/units.py +35 -0
- trueppm_api/apps/scheduling/urls.py +57 -0
- trueppm_api/apps/scheduling/views.py +2908 -0
- trueppm_api/apps/sso/__init__.py +0 -0
- trueppm_api/apps/sso/apps.py +19 -0
- trueppm_api/apps/sso/extensions.py +130 -0
- trueppm_api/apps/sso/management/__init__.py +0 -0
- trueppm_api/apps/sso/management/commands/__init__.py +0 -0
- trueppm_api/apps/sso/management/commands/seed_sso_keycloak.py +172 -0
- trueppm_api/apps/sso/migrations/0001_initial.py +119 -0
- trueppm_api/apps/sso/migrations/0002_remove_oidcprovider_workspace_ssoproviderpolicy_and_more.py +169 -0
- trueppm_api/apps/sso/migrations/__init__.py +0 -0
- trueppm_api/apps/sso/models.py +148 -0
- trueppm_api/apps/sso/serializers.py +446 -0
- trueppm_api/apps/sso/services.py +1473 -0
- trueppm_api/apps/sso/urls.py +47 -0
- trueppm_api/apps/sso/views.py +935 -0
- trueppm_api/apps/sync/__init__.py +0 -0
- trueppm_api/apps/sync/apps.py +15 -0
- trueppm_api/apps/sync/backfill.py +208 -0
- trueppm_api/apps/sync/broadcast.py +369 -0
- trueppm_api/apps/sync/conflict.py +262 -0
- trueppm_api/apps/sync/consumers.py +548 -0
- trueppm_api/apps/sync/migrations/0001_initial.py +59 -0
- trueppm_api/apps/sync/migrations/0001_squashed_0002_remove_syncbatch_syncbatch_project_client_batch_uniq_and_more.py +77 -0
- trueppm_api/apps/sync/migrations/0002_remove_syncbatch_syncbatch_project_client_batch_uniq_and_more.py +41 -0
- trueppm_api/apps/sync/migrations/0003_boardevent.py +46 -0
- trueppm_api/apps/sync/migrations/0003_squashed_0005_release_0_4.py +77 -0
- trueppm_api/apps/sync/migrations/0004_seed_sync_seq.py +24 -0
- trueppm_api/apps/sync/migrations/0005_program_sync_sequence.py +35 -0
- trueppm_api/apps/sync/migrations/0006_boardevent_per_project_seq.py +77 -0
- trueppm_api/apps/sync/migrations/__init__.py +0 -0
- trueppm_api/apps/sync/models.py +272 -0
- trueppm_api/apps/sync/pagination.py +231 -0
- trueppm_api/apps/sync/sequence.py +488 -0
- trueppm_api/apps/sync/serializers.py +688 -0
- trueppm_api/apps/sync/tasks.py +260 -0
- trueppm_api/apps/sync/throttles.py +175 -0
- trueppm_api/apps/sync/upload.py +556 -0
- trueppm_api/apps/sync/urls.py +17 -0
- trueppm_api/apps/sync/views.py +957 -0
- trueppm_api/apps/sync/ws_auth.py +193 -0
- trueppm_api/apps/taskruns/__init__.py +0 -0
- trueppm_api/apps/taskruns/apps.py +11 -0
- trueppm_api/apps/taskruns/migrations/0001_initial.py +92 -0
- trueppm_api/apps/taskruns/migrations/__init__.py +0 -0
- trueppm_api/apps/taskruns/models.py +68 -0
- trueppm_api/apps/taskruns/serializers.py +92 -0
- trueppm_api/apps/taskruns/tasks.py +60 -0
- trueppm_api/apps/taskruns/tracker.py +286 -0
- trueppm_api/apps/taskruns/urls.py +46 -0
- trueppm_api/apps/taskruns/views.py +195 -0
- trueppm_api/apps/teams/__init__.py +8 -0
- trueppm_api/apps/teams/apps.py +16 -0
- trueppm_api/apps/teams/migrations/0001_initial.py +139 -0
- trueppm_api/apps/teams/migrations/0001_squashed_0002_default_teams.py +159 -0
- trueppm_api/apps/teams/migrations/0002_default_teams.py +62 -0
- trueppm_api/apps/teams/migrations/0003_team_sync_seq_teammembership_sync_seq.py +22 -0
- trueppm_api/apps/teams/migrations/0004_backfill_default_teams_on_upgrade.py +49 -0
- trueppm_api/apps/teams/migrations/__init__.py +0 -0
- trueppm_api/apps/teams/models.py +145 -0
- trueppm_api/apps/teams/permissions.py +149 -0
- trueppm_api/apps/teams/serializers.py +95 -0
- trueppm_api/apps/teams/services.py +440 -0
- trueppm_api/apps/teams/signals.py +61 -0
- trueppm_api/apps/teams/urls.py +34 -0
- trueppm_api/apps/teams/views.py +201 -0
- trueppm_api/apps/timetracking/__init__.py +0 -0
- trueppm_api/apps/timetracking/apps.py +9 -0
- trueppm_api/apps/timetracking/migrations/0001_initial.py +117 -0
- trueppm_api/apps/timetracking/migrations/0001_squashed_0004_release_0_4.py +167 -0
- trueppm_api/apps/timetracking/migrations/0002_timesheetsubmission.py +46 -0
- trueppm_api/apps/timetracking/migrations/0003_timeentry_deleted_at_timeentry_deleted_by.py +31 -0
- trueppm_api/apps/timetracking/migrations/0004_timeentry_sync_seq_and_more.py +24 -0
- trueppm_api/apps/timetracking/migrations/__init__.py +0 -0
- trueppm_api/apps/timetracking/models.py +178 -0
- trueppm_api/apps/timetracking/serializers.py +175 -0
- trueppm_api/apps/timetracking/services.py +211 -0
- trueppm_api/apps/timetracking/urls.py +47 -0
- trueppm_api/apps/timetracking/views.py +597 -0
- trueppm_api/apps/webhooks/__init__.py +0 -0
- trueppm_api/apps/webhooks/apps.py +8 -0
- trueppm_api/apps/webhooks/backfill.py +90 -0
- trueppm_api/apps/webhooks/dispatch.py +279 -0
- trueppm_api/apps/webhooks/migrations/0001_initial.py +146 -0
- trueppm_api/apps/webhooks/migrations/0001_squashed_0007_sprint_lifecycle_events.py +249 -0
- trueppm_api/apps/webhooks/migrations/0002_alter_webhook_events.py +32 -0
- trueppm_api/apps/webhooks/migrations/0003_delivery_status_created_idx.py +17 -0
- trueppm_api/apps/webhooks/migrations/0004_webhook_program_alter_webhook_project_and_more.py +64 -0
- trueppm_api/apps/webhooks/migrations/0005_webhook_delivery_sequence_numbers.py +30 -0
- trueppm_api/apps/webhooks/migrations/0006_webhook_format_alter_webhook_events_and_more.py +61 -0
- trueppm_api/apps/webhooks/migrations/0007_sprint_lifecycle_events.py +63 -0
- trueppm_api/apps/webhooks/migrations/0008_risk_baseline_comment_events.py +73 -0
- trueppm_api/apps/webhooks/migrations/0009_encrypt_webhook_secret_and_failure_counters.py +100 -0
- trueppm_api/apps/webhooks/migrations/0010_alter_webhook_disabled_at.py +21 -0
- trueppm_api/apps/webhooks/migrations/0011_webhookeditor.py +48 -0
- trueppm_api/apps/webhooks/migrations/0012_alter_webhook_disabled_at.py +21 -0
- trueppm_api/apps/webhooks/migrations/__init__.py +0 -0
- trueppm_api/apps/webhooks/models.py +437 -0
- trueppm_api/apps/webhooks/serializers.py +326 -0
- trueppm_api/apps/webhooks/tasks.py +680 -0
- trueppm_api/apps/webhooks/urls.py +22 -0
- trueppm_api/apps/webhooks/views.py +533 -0
- trueppm_api/apps/workflow_engine/__init__.py +0 -0
- trueppm_api/apps/workflow_engine/apps.py +23 -0
- trueppm_api/apps/workflow_engine/migrations/0001_initial.py +230 -0
- trueppm_api/apps/workflow_engine/migrations/0001_squashed_0002_remove_workflowhistoryevent_workflow_history_lookup_idx.py +234 -0
- trueppm_api/apps/workflow_engine/migrations/0002_remove_workflowhistoryevent_workflow_history_lookup_idx.py +16 -0
- trueppm_api/apps/workflow_engine/migrations/0003_workflowoutboxrow_workflow_outbox_recovery_idx.py +21 -0
- trueppm_api/apps/workflow_engine/migrations/__init__.py +0 -0
- trueppm_api/apps/workflow_engine/models.py +265 -0
- trueppm_api/apps/workflow_engine/tasks.py +371 -0
- trueppm_api/apps/workspace/__init__.py +0 -0
- trueppm_api/apps/workspace/apps.py +10 -0
- trueppm_api/apps/workspace/backfill.py +111 -0
- trueppm_api/apps/workspace/export.py +254 -0
- trueppm_api/apps/workspace/migrations/0001_initial.py +326 -0
- trueppm_api/apps/workspace/migrations/0001_squashed_0014_workspacemembership_availability_effective_from_and_more.py +829 -0
- trueppm_api/apps/workspace/migrations/0002_remove_workspace_fiscal_year_start_and_more.py +85 -0
- trueppm_api/apps/workspace/migrations/0003_workspaceexportjob.py +73 -0
- trueppm_api/apps/workspace/migrations/0004_alter_workspaceinvite_status.py +27 -0
- trueppm_api/apps/workspace/migrations/0005_workspace_iteration_label_and_more.py +26 -0
- trueppm_api/apps/workspace/migrations/0006_alter_groupmembership_unique_together_and_more.py +45 -0
- trueppm_api/apps/workspace/migrations/0007_workspace_public_sharing_override_policy.py +21 -0
- trueppm_api/apps/workspace/migrations/0008_workspace_mc_history_attribution_audience_and_more.py +44 -0
- trueppm_api/apps/workspace/migrations/0009_workspace_methodology_and_more.py +186 -0
- trueppm_api/apps/workspace/migrations/0010_workspace_logo.py +38 -0
- trueppm_api/apps/workspace/migrations/0011_historicalworkspace_task_duration_change_percent_override_policy_and_more.py +56 -0
- trueppm_api/apps/workspace/migrations/0012_historicalworkspace_allowed_attachment_types_and_more.py +64 -0
- trueppm_api/apps/workspace/migrations/0013_auditevent.py +70 -0
- trueppm_api/apps/workspace/migrations/0014_workspacemembership_availability_effective_from_and_more.py +39 -0
- trueppm_api/apps/workspace/migrations/0015_squashed_0027_release_0_4.py +199 -0
- trueppm_api/apps/workspace/migrations/0015_trash_restore_1113.py +34 -0
- trueppm_api/apps/workspace/migrations/0016_historicalworkspace_calendar_and_more.py +55 -0
- trueppm_api/apps/workspace/migrations/0017_historicalworkspace_estimation_scale_and_more.py +38 -0
- trueppm_api/apps/workspace/migrations/0018_historicalworkspace_feedback_enabled_and_more.py +32 -0
- trueppm_api/apps/workspace/migrations/0019_historicalworkspace_mcp_enabled_and_more.py +22 -0
- trueppm_api/apps/workspace/migrations/0020_viewer_ordinal_one.py +34 -0
- trueppm_api/apps/workspace/migrations/0021_group_sync_seq_groupmembership_sync_seq_and_more.py +27 -0
- trueppm_api/apps/workspace/migrations/0022_historicalworkspace_sprint_picker_ready_only_default_and_more.py +22 -0
- trueppm_api/apps/workspace/migrations/0023_alter_auditevent_event_type.py +32 -0
- trueppm_api/apps/workspace/migrations/0024_alter_auditevent_event_type.py +33 -0
- trueppm_api/apps/workspace/migrations/0025_alter_auditevent_event_type.py +36 -0
- trueppm_api/apps/workspace/migrations/0026_alter_auditevent_event_type.py +37 -0
- trueppm_api/apps/workspace/migrations/0027_alter_auditevent_event_type.py +42 -0
- trueppm_api/apps/workspace/migrations/__init__.py +0 -0
- trueppm_api/apps/workspace/models.py +857 -0
- trueppm_api/apps/workspace/permissions.py +187 -0
- trueppm_api/apps/workspace/serializers.py +590 -0
- trueppm_api/apps/workspace/services.py +967 -0
- trueppm_api/apps/workspace/signals.py +37 -0
- trueppm_api/apps/workspace/tasks.py +616 -0
- trueppm_api/apps/workspace/urls.py +113 -0
- trueppm_api/apps/workspace/views.py +1581 -0
- trueppm_api/asgi.py +49 -0
- trueppm_api/celery.py +40 -0
- trueppm_api/core/__init__.py +0 -0
- trueppm_api/core/admin_site.py +206 -0
- trueppm_api/core/auth_views.py +934 -0
- trueppm_api/core/constant_time.py +51 -0
- trueppm_api/core/csp.py +54 -0
- trueppm_api/core/db.py +87 -0
- trueppm_api/core/db_session.py +37 -0
- trueppm_api/core/demo_read_only.py +314 -0
- trueppm_api/core/exception_handlers.py +157 -0
- trueppm_api/core/export_downloads.py +56 -0
- trueppm_api/core/extension_providers.py +56 -0
- trueppm_api/core/extension_signals.py +147 -0
- trueppm_api/core/idempotent.py +260 -0
- trueppm_api/core/metadata.py +42 -0
- trueppm_api/core/middleware.py +51 -0
- trueppm_api/core/openapi.py +1221 -0
- trueppm_api/core/password_reset.py +513 -0
- trueppm_api/core/protect_conflict.py +100 -0
- trueppm_api/core/ratelimit.py +148 -0
- trueppm_api/core/redis_throttle.py +82 -0
- trueppm_api/core/refresh_cookie_policy.py +156 -0
- trueppm_api/core/request_body.py +86 -0
- trueppm_api/core/security_checks.py +1034 -0
- trueppm_api/core/storage_config.py +105 -0
- trueppm_api/core/text_decode.py +168 -0
- trueppm_api/core/throttling.py +514 -0
- trueppm_api/core/valkey.py +214 -0
- trueppm_api/core/valkey_cache.py +66 -0
- trueppm_api/core/valkey_checks.py +104 -0
- trueppm_api/core/valkey_config.py +39 -0
- trueppm_api/core/worker_broker_wait.py +149 -0
- trueppm_api/core/worker_heartbeat.py +134 -0
- trueppm_api/core/worker_selfheal.py +205 -0
- trueppm_api/fields.py +36 -0
- trueppm_api/permissions.py +30 -0
- trueppm_api/py.typed +0 -0
- trueppm_api/routing.py +11 -0
- trueppm_api/settings/__init__.py +0 -0
- trueppm_api/settings/base.py +2605 -0
- trueppm_api/settings/dev.py +296 -0
- trueppm_api/settings/prod.py +265 -0
- trueppm_api/urls.py +217 -0
- trueppm_api/workflows/__init__.py +38 -0
- trueppm_api/workflows/backends/__init__.py +6 -0
- trueppm_api/workflows/backends/default.py +297 -0
- trueppm_api/workflows/consumers/__init__.py +11 -0
- trueppm_api/workflows/consumers/requeue_failed_task.py +65 -0
- trueppm_api/workflows/interface.py +148 -0
- trueppm_api/workflows/registry.py +106 -0
- trueppm_api/workflows/services.py +90 -0
- trueppm_api/wsgi.py +11 -0
- trueppm_api-0.4.0.dist-info/METADATA +273 -0
- trueppm_api-0.4.0.dist-info/RECORD +799 -0
- trueppm_api-0.4.0.dist-info/WHEEL +4 -0
- trueppm_api-0.4.0.dist-info/licenses/LICENSE +201 -0
- trueppm_api-0.4.0.dist-info/licenses/NOTICE +7 -0
- trueppm_api-0.4.0.dist-info/licenses/NOTICES +104 -0
- trueppm_api-0.4.0.dist-info/licenses/licenses/GPL-3.0.txt +674 -0
- trueppm_api-0.4.0.dist-info/licenses/licenses/LGPL-3.0.txt +165 -0
- trueppm_api-0.4.0.dist-info/licenses/licenses/MPL-2.0.txt +373 -0
|
@@ -0,0 +1,688 @@
|
|
|
1
|
+
"""Serializers for the sync pull endpoint.
|
|
2
|
+
|
|
3
|
+
Sync serializers always include server_version and is_deleted so mobile
|
|
4
|
+
clients can track changes precisely. They are intentionally separate from
|
|
5
|
+
the CRUD serializers — their contract is with the mobile offline store,
|
|
6
|
+
not the REST API consumer.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import uuid
|
|
12
|
+
from collections.abc import Iterator
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from rest_framework import serializers
|
|
16
|
+
|
|
17
|
+
from trueppm_api.apps.access.models import ProgramMembership, ProjectMembership
|
|
18
|
+
from trueppm_api.apps.integrations.models import TaskLink
|
|
19
|
+
from trueppm_api.apps.projects.models import (
|
|
20
|
+
Calendar,
|
|
21
|
+
Dependency,
|
|
22
|
+
Label,
|
|
23
|
+
Program,
|
|
24
|
+
Project,
|
|
25
|
+
RetroActionItem,
|
|
26
|
+
Risk,
|
|
27
|
+
Sprint,
|
|
28
|
+
SprintRetro,
|
|
29
|
+
Task,
|
|
30
|
+
TaskRecurrenceRule,
|
|
31
|
+
TaskRelation,
|
|
32
|
+
TaskSuggestedAssignee,
|
|
33
|
+
)
|
|
34
|
+
from trueppm_api.apps.projects.serializers import CalendarExceptionSerializer
|
|
35
|
+
from trueppm_api.apps.timetracking.models import TimeEntry
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _is_uuid(value: object) -> bool:
|
|
39
|
+
"""True if ``value`` parses as a UUID (the PK type of every synced row)."""
|
|
40
|
+
try:
|
|
41
|
+
uuid.UUID(str(value))
|
|
42
|
+
except (ValueError, TypeError, AttributeError):
|
|
43
|
+
return False
|
|
44
|
+
return True
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _iter_upload_row_ids(attrs: dict[str, Any]) -> Iterator[object]:
|
|
48
|
+
"""Yield every row id in an upload envelope: the ``id`` of each created/updated
|
|
49
|
+
row and each bare ``deleted`` id.
|
|
50
|
+
|
|
51
|
+
Rows are free-form ``DictField``s, so the id lives inside the row for
|
|
52
|
+
created/updated and is a bare string for deleted. Non-dict created/updated rows
|
|
53
|
+
carry no id and are skipped (they were surfaced as a ``None`` candidate before,
|
|
54
|
+
which the empty/absent-id filter dropped anyway — behavior is unchanged).
|
|
55
|
+
"""
|
|
56
|
+
for bucket in ("created", "updated"):
|
|
57
|
+
for row in attrs.get(bucket, []) or []:
|
|
58
|
+
if isinstance(row, dict):
|
|
59
|
+
yield row.get("id")
|
|
60
|
+
yield from attrs.get("deleted", []) or []
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class SyncCalendarSerializer(serializers.ModelSerializer[Calendar]):
|
|
64
|
+
"""Sync payload for Calendar. Exceptions ride the aggregate root (ADR-0193).
|
|
65
|
+
|
|
66
|
+
Exceptions are nested read-only rather than given their own sync collection:
|
|
67
|
+
they have no server_version of their own, and every exception write bumps the
|
|
68
|
+
parent Calendar.server_version, so a client that pulls the changed calendar
|
|
69
|
+
delta receives the full, current exception set inline. Critical-path math is
|
|
70
|
+
therefore holiday-aware offline.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
exceptions = CalendarExceptionSerializer(many=True, read_only=True)
|
|
74
|
+
|
|
75
|
+
class Meta:
|
|
76
|
+
model = Calendar
|
|
77
|
+
fields = [
|
|
78
|
+
"id",
|
|
79
|
+
"server_version",
|
|
80
|
+
"name",
|
|
81
|
+
"working_days",
|
|
82
|
+
"hours_per_day",
|
|
83
|
+
"timezone",
|
|
84
|
+
"exceptions",
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
def validate_timezone(self, value: str) -> str:
|
|
88
|
+
"""Reject a non-IANA zone — same form as ``CalendarSerializer``.
|
|
89
|
+
|
|
90
|
+
Sync serves this serializer in the pull direction only today
|
|
91
|
+
(``upload.WRITABLE_COLLECTIONS`` names ``tasks`` alone), so this never runs;
|
|
92
|
+
it exists so that a push path added later inherits the write-time check every
|
|
93
|
+
other ``timezone`` field carries, rather than becoming the next unvalidated
|
|
94
|
+
write path.
|
|
95
|
+
"""
|
|
96
|
+
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
|
97
|
+
|
|
98
|
+
stripped = (value or "").strip()
|
|
99
|
+
try:
|
|
100
|
+
ZoneInfo(stripped)
|
|
101
|
+
except (ZoneInfoNotFoundError, ValueError, OSError) as exc:
|
|
102
|
+
raise serializers.ValidationError("Unknown IANA timezone.") from exc
|
|
103
|
+
return stripped
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class SyncProjectSerializer(serializers.ModelSerializer[Project]):
|
|
107
|
+
"""Sync payload for Project — minimal shape consumed by the WatermelonDB Project table.
|
|
108
|
+
|
|
109
|
+
``program`` (ADR-0070) is included so mobile can render the program badge
|
|
110
|
+
on project rows offline. Program and ProgramMembership tables themselves
|
|
111
|
+
are not yet wired into mobile sync — the existing endpoint is project-scoped
|
|
112
|
+
and cannot reach user-scoped Program rows. Mobile-side Program sync is
|
|
113
|
+
tracked as a follow-up; for now mobile uses the REST endpoints online and
|
|
114
|
+
falls back to the cached project rows (with their ``program`` FK) offline.
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
class Meta:
|
|
118
|
+
model = Project
|
|
119
|
+
fields = [
|
|
120
|
+
"id",
|
|
121
|
+
"server_version",
|
|
122
|
+
"name",
|
|
123
|
+
"description",
|
|
124
|
+
"start_date",
|
|
125
|
+
"calendar",
|
|
126
|
+
"program",
|
|
127
|
+
]
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class SyncTaskSerializer(serializers.ModelSerializer[Task]):
|
|
131
|
+
"""Sync payload for Task — full CPM and baseline fields for offline scheduling previews."""
|
|
132
|
+
|
|
133
|
+
# Computed (ADR-0293): a non-subtask task with >=1 structural (non-subtask)
|
|
134
|
+
# child is a phase — a pure rollup whose status/estimate/assignee/percent are
|
|
135
|
+
# derived from its children. Read-only; annotated onto the sync tasks queryset
|
|
136
|
+
# in the pull view. ``default=False`` makes it safe if the annotation is absent
|
|
137
|
+
# (e.g. a bare instance in a test), matching TaskSerializer.is_phase.
|
|
138
|
+
is_phase = serializers.BooleanField(read_only=True, default=False)
|
|
139
|
+
|
|
140
|
+
# Task labels ride the task's own ``server_version`` as a flat id array rather
|
|
141
|
+
# than a synced join table (ADR-0400, mirroring SyncRiskSerializer.task_ids).
|
|
142
|
+
# Attaching/detaching a label bumps ``Task.server_version`` so this delta pulls.
|
|
143
|
+
# The pull view prefetches ``labels`` to avoid N+1.
|
|
144
|
+
label_ids = serializers.SerializerMethodField()
|
|
145
|
+
|
|
146
|
+
def get_label_ids(self, obj: Task) -> list[str]:
|
|
147
|
+
# Iterate the prefetched cache; values_list() bypasses it and fires an extra SELECT.
|
|
148
|
+
return [str(label.pk) for label in obj.labels.all()]
|
|
149
|
+
|
|
150
|
+
# Per-task custom-field values (#2143, ADR-0528) ride Task.server_version exactly like
|
|
151
|
+
# label_ids — the same flat {field_id: value} map the online Task payload carries, fed
|
|
152
|
+
# by the same prefetch. NB: offline *rendering* additionally needs the field definitions
|
|
153
|
+
# synced (deferred per ADR-0528); this map is forward-compatible until that lands.
|
|
154
|
+
custom_fields = serializers.SerializerMethodField()
|
|
155
|
+
|
|
156
|
+
def get_custom_fields(self, obj: Task) -> dict[str, Any]:
|
|
157
|
+
from trueppm_api.apps.projects.custom_field_values import build_custom_fields_map
|
|
158
|
+
|
|
159
|
+
return build_custom_fields_map(obj)
|
|
160
|
+
|
|
161
|
+
class Meta:
|
|
162
|
+
model = Task
|
|
163
|
+
fields = [
|
|
164
|
+
"id",
|
|
165
|
+
"server_version",
|
|
166
|
+
"short_id",
|
|
167
|
+
"project",
|
|
168
|
+
"name",
|
|
169
|
+
"wbs_path",
|
|
170
|
+
"status",
|
|
171
|
+
"duration",
|
|
172
|
+
"percent_complete",
|
|
173
|
+
"notes",
|
|
174
|
+
"planned_start",
|
|
175
|
+
"early_start",
|
|
176
|
+
"early_finish",
|
|
177
|
+
"scheduled_start",
|
|
178
|
+
"late_start",
|
|
179
|
+
"late_finish",
|
|
180
|
+
"total_float",
|
|
181
|
+
"free_float",
|
|
182
|
+
"is_critical",
|
|
183
|
+
"milestone_at_day_end",
|
|
184
|
+
"is_milestone",
|
|
185
|
+
"actual_start",
|
|
186
|
+
"actual_finish",
|
|
187
|
+
"optimistic_duration",
|
|
188
|
+
"most_likely_duration",
|
|
189
|
+
"pessimistic_duration",
|
|
190
|
+
"is_subtask",
|
|
191
|
+
"sprint",
|
|
192
|
+
"assignee",
|
|
193
|
+
"is_phase",
|
|
194
|
+
"label_ids",
|
|
195
|
+
"custom_fields",
|
|
196
|
+
]
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class SyncDependencySerializer(serializers.ModelSerializer[Dependency]):
|
|
200
|
+
"""Sync payload for Dependency links — includes server_version for delta tracking."""
|
|
201
|
+
|
|
202
|
+
class Meta:
|
|
203
|
+
model = Dependency
|
|
204
|
+
fields = ["id", "server_version", "predecessor", "successor", "dep_type", "lag"]
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class SyncTaskRelationSerializer(serializers.ModelSerializer[TaskRelation]):
|
|
208
|
+
"""Sync payload for informational TaskRelation links (ADR-0455).
|
|
209
|
+
|
|
210
|
+
Pull-only, mirroring :class:`SyncDependencySerializer`: a relation is inert, so
|
|
211
|
+
the offline store needs only the endpoints, kind, and note plus the delta
|
|
212
|
+
bookkeeping (``server_version`` / ``is_deleted``) to reconcile. Not writable
|
|
213
|
+
from the client — it is deliberately absent from the sync-upload
|
|
214
|
+
WRITABLE_COLLECTIONS, exactly like Dependency.
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
class Meta:
|
|
218
|
+
model = TaskRelation
|
|
219
|
+
fields = [
|
|
220
|
+
"id",
|
|
221
|
+
"server_version",
|
|
222
|
+
"source",
|
|
223
|
+
"target",
|
|
224
|
+
"relation_type",
|
|
225
|
+
"note",
|
|
226
|
+
"is_deleted",
|
|
227
|
+
]
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
class SyncMembershipSerializer(serializers.ModelSerializer[ProjectMembership]):
|
|
231
|
+
"""Sync payload for ProjectMembership — lets mobile clients enforce offline RBAC.
|
|
232
|
+
|
|
233
|
+
``reinstated_at`` rides the delta (#3436) so an offline client can tell a
|
|
234
|
+
revived membership apart from one that never lapsed, the same discriminator
|
|
235
|
+
the online read serializer exposes — null iff this row has never been
|
|
236
|
+
revoked and re-added.
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
class Meta:
|
|
240
|
+
model = ProjectMembership
|
|
241
|
+
fields = ["id", "server_version", "project", "user", "role", "reinstated_at"]
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
class SyncProgramSerializer(serializers.ModelSerializer[Program]):
|
|
245
|
+
"""Sync payload for Program (ADR-0070 §Sync, #561).
|
|
246
|
+
|
|
247
|
+
Minimal shape the offline store needs to render the program list card and
|
|
248
|
+
header when the device has no signal: name/description/code/methodology plus
|
|
249
|
+
the display accents (health, color, target_date, lead). Rollup KPIs, sharing
|
|
250
|
+
overrides, and ceremony config are intentionally excluded — they are online-
|
|
251
|
+
only surfaces. Delivered by the user-scoped :class:`UserProgramSyncView`, the
|
|
252
|
+
endpoint ADR-0070 §Sync flagged as the 0.4 follow-up.
|
|
253
|
+
"""
|
|
254
|
+
|
|
255
|
+
class Meta:
|
|
256
|
+
model = Program
|
|
257
|
+
fields = [
|
|
258
|
+
"id",
|
|
259
|
+
"server_version",
|
|
260
|
+
"name",
|
|
261
|
+
"description",
|
|
262
|
+
"code",
|
|
263
|
+
"methodology",
|
|
264
|
+
"health",
|
|
265
|
+
"color",
|
|
266
|
+
"target_date",
|
|
267
|
+
"lead",
|
|
268
|
+
]
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
class SyncProgramMembershipSerializer(serializers.ModelSerializer[ProgramMembership]):
|
|
272
|
+
"""Sync payload for ProgramMembership — lets clients enforce offline program RBAC.
|
|
273
|
+
|
|
274
|
+
Mirrors :class:`SyncMembershipSerializer` (project membership) exactly: only
|
|
275
|
+
``(program, user, role)`` plus the sync bookkeeping fields and
|
|
276
|
+
``reinstated_at`` (#3436). The User table is not synced, so ``user`` is the
|
|
277
|
+
FK id — the client resolves display names from its own cached roster,
|
|
278
|
+
identical to the project-membership sync behaviour.
|
|
279
|
+
"""
|
|
280
|
+
|
|
281
|
+
class Meta:
|
|
282
|
+
model = ProgramMembership
|
|
283
|
+
fields = ["id", "server_version", "program", "user", "role", "reinstated_at"]
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
class SyncSprintSerializer(serializers.ModelSerializer[Sprint]):
|
|
287
|
+
"""Sync payload for Sprint — enables offline sprint context for retros (ADR-0071)."""
|
|
288
|
+
|
|
289
|
+
class Meta:
|
|
290
|
+
model = Sprint
|
|
291
|
+
fields = [
|
|
292
|
+
"id",
|
|
293
|
+
"server_version",
|
|
294
|
+
"short_id",
|
|
295
|
+
"project",
|
|
296
|
+
"name",
|
|
297
|
+
"goal",
|
|
298
|
+
"start_date",
|
|
299
|
+
"finish_date",
|
|
300
|
+
"state",
|
|
301
|
+
]
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
class SyncSprintRetroSerializer(serializers.ModelSerializer[SprintRetro]):
|
|
305
|
+
"""Sync payload for SprintRetro (ADR-0071).
|
|
306
|
+
|
|
307
|
+
Mobile receives the raw notes only when the caller's role meets the
|
|
308
|
+
retro's team_visibility threshold; the sync view is responsible for
|
|
309
|
+
filtering retros the caller cannot see. WatermelonDB stores what it
|
|
310
|
+
receives — the server-side visibility gate is the only check.
|
|
311
|
+
"""
|
|
312
|
+
|
|
313
|
+
class Meta:
|
|
314
|
+
model = SprintRetro
|
|
315
|
+
fields = [
|
|
316
|
+
"id",
|
|
317
|
+
"server_version",
|
|
318
|
+
"sprint",
|
|
319
|
+
"notes",
|
|
320
|
+
"team_visibility",
|
|
321
|
+
"created_by",
|
|
322
|
+
"created_at",
|
|
323
|
+
"updated_at",
|
|
324
|
+
]
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
class SyncRetroActionItemSerializer(serializers.ModelSerializer[RetroActionItem]):
|
|
328
|
+
"""Sync payload for RetroActionItem (ADR-0071)."""
|
|
329
|
+
|
|
330
|
+
class Meta:
|
|
331
|
+
model = RetroActionItem
|
|
332
|
+
fields = [
|
|
333
|
+
"id",
|
|
334
|
+
"server_version",
|
|
335
|
+
"retro",
|
|
336
|
+
"text",
|
|
337
|
+
"assignee",
|
|
338
|
+
"story_points",
|
|
339
|
+
"promoted_task_id",
|
|
340
|
+
"created_at",
|
|
341
|
+
]
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
class SyncTaskSuggestedAssigneeSerializer(serializers.ModelSerializer[TaskSuggestedAssignee]):
|
|
345
|
+
"""Sync payload for TaskSuggestedAssignee (ADR-0071 §5)."""
|
|
346
|
+
|
|
347
|
+
class Meta:
|
|
348
|
+
model = TaskSuggestedAssignee
|
|
349
|
+
fields = [
|
|
350
|
+
"id",
|
|
351
|
+
"server_version",
|
|
352
|
+
"task",
|
|
353
|
+
"suggested_user",
|
|
354
|
+
"suggested_by",
|
|
355
|
+
"reason",
|
|
356
|
+
"source",
|
|
357
|
+
"state",
|
|
358
|
+
"created_at",
|
|
359
|
+
"accepted_at",
|
|
360
|
+
"declined_at",
|
|
361
|
+
]
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
class SyncTaskLinkSerializer(serializers.ModelSerializer[TaskLink]):
|
|
365
|
+
"""Sync payload for TaskLink (ADR-0049 §3, #637) — links on a task.
|
|
366
|
+
|
|
367
|
+
Carries the cloud-file preview cache (#571, ADR-0163) so the preview card
|
|
368
|
+
renders offline on the mobile client straight from the sync delta.
|
|
369
|
+
"""
|
|
370
|
+
|
|
371
|
+
class Meta:
|
|
372
|
+
model = TaskLink
|
|
373
|
+
fields = [
|
|
374
|
+
"id",
|
|
375
|
+
"server_version",
|
|
376
|
+
"task",
|
|
377
|
+
"url",
|
|
378
|
+
"provider",
|
|
379
|
+
"title",
|
|
380
|
+
"custom_title",
|
|
381
|
+
"labels",
|
|
382
|
+
"status",
|
|
383
|
+
"fetched_at",
|
|
384
|
+
"description",
|
|
385
|
+
"thumbnail_url",
|
|
386
|
+
"preview_type",
|
|
387
|
+
"display_order",
|
|
388
|
+
]
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
class SyncTaskRecurrenceRuleSerializer(serializers.ModelSerializer[TaskRecurrenceRule]):
|
|
392
|
+
"""Sync payload for TaskRecurrenceRule (ADR-0090).
|
|
393
|
+
|
|
394
|
+
Omits the internal ``generated_through`` cursor — mobile clients recompute the
|
|
395
|
+
occurrence preview from the rule fields and never need the server-side cursor.
|
|
396
|
+
"""
|
|
397
|
+
|
|
398
|
+
class Meta:
|
|
399
|
+
model = TaskRecurrenceRule
|
|
400
|
+
fields = [
|
|
401
|
+
"id",
|
|
402
|
+
"server_version",
|
|
403
|
+
"task",
|
|
404
|
+
"frequency",
|
|
405
|
+
"interval",
|
|
406
|
+
"weekdays",
|
|
407
|
+
"day_of_month",
|
|
408
|
+
"time_of_day",
|
|
409
|
+
"timezone",
|
|
410
|
+
"end_type",
|
|
411
|
+
"end_date",
|
|
412
|
+
"end_count",
|
|
413
|
+
"inherit_assignee",
|
|
414
|
+
"inherit_subtasks",
|
|
415
|
+
"inherit_attachments",
|
|
416
|
+
"inherit_morning_notification",
|
|
417
|
+
]
|
|
418
|
+
|
|
419
|
+
def validate_timezone(self, value: str) -> str:
|
|
420
|
+
"""Reject a non-IANA zone — same form as ``CalendarSerializer``.
|
|
421
|
+
|
|
422
|
+
Sync serves this serializer in the pull direction only today
|
|
423
|
+
(``upload.WRITABLE_COLLECTIONS`` names ``tasks`` alone), so this never runs;
|
|
424
|
+
it exists so that a push path added later inherits the write-time check every
|
|
425
|
+
other ``timezone`` field carries, rather than becoming the next unvalidated
|
|
426
|
+
write path.
|
|
427
|
+
"""
|
|
428
|
+
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
|
429
|
+
|
|
430
|
+
stripped = (value or "").strip()
|
|
431
|
+
try:
|
|
432
|
+
ZoneInfo(stripped)
|
|
433
|
+
except (ZoneInfoNotFoundError, ValueError, OSError) as exc:
|
|
434
|
+
raise serializers.ValidationError("Unknown IANA timezone.") from exc
|
|
435
|
+
return stripped
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
class SyncRiskSerializer(serializers.ModelSerializer[Risk]):
|
|
439
|
+
"""Sync serializer for the Risk model.
|
|
440
|
+
|
|
441
|
+
task_ids is serialized as a flat list of task UUIDs (string) rather than
|
|
442
|
+
a nested M2M sync table. Expected cardinality is 1–10 tasks per risk, so
|
|
443
|
+
a JSON column on the WatermelonDB Risk record is simpler and sufficient.
|
|
444
|
+
The queryset in ProjectSyncView prefetches tasks to avoid N+1.
|
|
445
|
+
"""
|
|
446
|
+
|
|
447
|
+
task_ids = serializers.SerializerMethodField()
|
|
448
|
+
|
|
449
|
+
def get_task_ids(self, obj: Risk) -> list[str]:
|
|
450
|
+
# Iterate the prefetched cache; values_list() bypasses it and fires an extra SELECT.
|
|
451
|
+
return [str(t.pk) for t in obj.tasks.all()]
|
|
452
|
+
|
|
453
|
+
class Meta:
|
|
454
|
+
model = Risk
|
|
455
|
+
fields = [
|
|
456
|
+
"id",
|
|
457
|
+
"server_version",
|
|
458
|
+
"short_id",
|
|
459
|
+
"project",
|
|
460
|
+
"title",
|
|
461
|
+
"description",
|
|
462
|
+
"status",
|
|
463
|
+
"probability",
|
|
464
|
+
"impact",
|
|
465
|
+
"owner",
|
|
466
|
+
"task_ids",
|
|
467
|
+
]
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
class SyncLabelSerializer(serializers.ModelSerializer[Label]):
|
|
471
|
+
"""Sync payload for the project-scoped label catalog (ADR-0400).
|
|
472
|
+
|
|
473
|
+
The ``Label`` catalog syncs as its own ``VersionedModel`` collection (colors +
|
|
474
|
+
curated vocabulary need a table). Assignment to a task is NOT synced here — it
|
|
475
|
+
rides ``Task.server_version`` via ``SyncTaskSerializer.label_ids``. Soft-deleted
|
|
476
|
+
rows ride the standard tombstone path (``is_deleted``/``deleted_version``).
|
|
477
|
+
"""
|
|
478
|
+
|
|
479
|
+
class Meta:
|
|
480
|
+
model = Label
|
|
481
|
+
fields = [
|
|
482
|
+
"id",
|
|
483
|
+
"server_version",
|
|
484
|
+
"project",
|
|
485
|
+
"name",
|
|
486
|
+
"color",
|
|
487
|
+
"position",
|
|
488
|
+
]
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
class SyncTimeEntrySerializer(serializers.ModelSerializer[TimeEntry]):
|
|
492
|
+
"""Sync payload for TimeEntry (ADR-0185 §6).
|
|
493
|
+
|
|
494
|
+
The per-project delta is filtered to ``user=request.user`` in ``ProjectSyncView``,
|
|
495
|
+
so a client only ever receives its **own** entries — the same non-surveillance
|
|
496
|
+
discipline as the REST surface (a Member never pulls a colleague's entries). Soft-
|
|
497
|
+
deleted rows ride the standard tombstone path. ``ActiveTimer`` is deliberately not
|
|
498
|
+
synced (transient/derived; recovered via ``GET /me/timer/``).
|
|
499
|
+
"""
|
|
500
|
+
|
|
501
|
+
class Meta:
|
|
502
|
+
model = TimeEntry
|
|
503
|
+
fields = [
|
|
504
|
+
"id",
|
|
505
|
+
"server_version",
|
|
506
|
+
"task",
|
|
507
|
+
"user",
|
|
508
|
+
"minutes",
|
|
509
|
+
"entry_date",
|
|
510
|
+
"note",
|
|
511
|
+
"source",
|
|
512
|
+
"created_at",
|
|
513
|
+
]
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
# ---------------------------------------------------------------------------
|
|
517
|
+
# Pull (GET) response envelope — documents the paginated delta shape (#1013).
|
|
518
|
+
# ---------------------------------------------------------------------------
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
class SyncPullResponseSerializer(serializers.Serializer): # type: ignore[type-arg]
|
|
522
|
+
"""Response envelope for the paginated delta pull (#1013).
|
|
523
|
+
|
|
524
|
+
``next_cursor``/``has_more`` are added for cursor pagination; the pre-existing
|
|
525
|
+
``changes`` and ``timestamp`` fields are unchanged, so an older client that
|
|
526
|
+
ignores the cursor still gets a valid (first) page. The client loops while
|
|
527
|
+
``has_more`` is true, sending the previous ``next_cursor`` back and keeping
|
|
528
|
+
``since`` constant, then adopts ``timestamp`` as the next ``since``.
|
|
529
|
+
"""
|
|
530
|
+
|
|
531
|
+
changes = serializers.DictField(
|
|
532
|
+
help_text="Per-collection WatermelonDB buckets (created/updated/deleted).",
|
|
533
|
+
)
|
|
534
|
+
timestamp = serializers.IntegerField(
|
|
535
|
+
help_text=(
|
|
536
|
+
"High-water mark to adopt as `since` once the delta is fully drained "
|
|
537
|
+
"(after the last page). Pinned when the session's first page is served "
|
|
538
|
+
"and identical on every page of that session. On the project pull, "
|
|
539
|
+
"whose cursor is the project's monotonic `sync_seq`, that means a row "
|
|
540
|
+
"written into an already-drained collection mid-drain still falls above "
|
|
541
|
+
"the adopted checkpoint and arrives on the next pull. The program pull "
|
|
542
|
+
"keys on the per-row `server_version` rather than a session sequence, "
|
|
543
|
+
"so pinning stops its checkpoint climbing mid-drain but does not yet "
|
|
544
|
+
"deliver that guarantee — see issue #2498."
|
|
545
|
+
),
|
|
546
|
+
)
|
|
547
|
+
next_cursor = serializers.CharField(
|
|
548
|
+
allow_null=True,
|
|
549
|
+
help_text=(
|
|
550
|
+
"Opaque continuation token. Pass it as the `cursor` query param on the "
|
|
551
|
+
"next request; `null` when the delta is exhausted."
|
|
552
|
+
),
|
|
553
|
+
)
|
|
554
|
+
has_more = serializers.BooleanField(
|
|
555
|
+
help_text=(
|
|
556
|
+
"DEPRECATED — removed in 0.5. True while more pages remain for this "
|
|
557
|
+
"`since` session. Exactly equivalent to `next_cursor is not null`; loop "
|
|
558
|
+
"on that instead. Announced here rather than removed in 0.4 (#2842) "
|
|
559
|
+
"because a client following the published drain loop would read "
|
|
560
|
+
"`undefined`, treat it as false, and silently stop after page one — "
|
|
561
|
+
"missing data presented as a complete sync."
|
|
562
|
+
),
|
|
563
|
+
)
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
# ---------------------------------------------------------------------------
|
|
567
|
+
# Upload (push) serializer — mobile offline → server (ADR-0082, issue #667)
|
|
568
|
+
#
|
|
569
|
+
# Validates only the batch envelope. Per-row task validation reuses the REST
|
|
570
|
+
# TaskSerializer (in sync.upload) so mobile writes inherit identical field
|
|
571
|
+
# rules and business logic — see ADR-0082 §E.
|
|
572
|
+
# ---------------------------------------------------------------------------
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
class SyncUploadCollectionSerializer(serializers.Serializer): # type: ignore[type-arg]
|
|
576
|
+
"""WatermelonDB per-collection change buckets — created / updated / deleted.
|
|
577
|
+
|
|
578
|
+
Mirrors the shape WatermelonDB's ``synchronize()`` pushes for one collection:
|
|
579
|
+
``created`` and ``updated`` are lists of full row objects, ``deleted`` is a
|
|
580
|
+
list of record ids (UUID strings). Row objects are deliberately free-form
|
|
581
|
+
(``DictField``) rather than a typed row serializer: per-field task validation
|
|
582
|
+
is delegated to ``TaskSerializer`` inside ``sync.upload`` so mobile writes
|
|
583
|
+
inherit identical field rules and business logic (ADR-0082 §E). All three
|
|
584
|
+
buckets are optional; an absent bucket means "no changes of that kind".
|
|
585
|
+
"""
|
|
586
|
+
|
|
587
|
+
created = serializers.ListField(child=serializers.DictField(), required=False)
|
|
588
|
+
updated = serializers.ListField(child=serializers.DictField(), required=False)
|
|
589
|
+
deleted = serializers.ListField(child=serializers.CharField(), required=False)
|
|
590
|
+
|
|
591
|
+
def validate(self, attrs: dict[str, Any]) -> dict[str, Any]:
|
|
592
|
+
# #1730: every row id here reaches a ``Task.objects.filter(pk__in=...)``
|
|
593
|
+
# in ``sync.upload``. A malformed (non-UUID) id would raise a django-core
|
|
594
|
+
# ValidationError/ValueError at query build that DRF does not catch → 500.
|
|
595
|
+
# Validate the ids up front so a bad one is a clean 400. Empty/absent ids are
|
|
596
|
+
# left to ``sync.upload``'s existing "each row requires an 'id'" guard so its
|
|
597
|
+
# message is unchanged.
|
|
598
|
+
bad = [
|
|
599
|
+
str(row_id) for row_id in _iter_upload_row_ids(attrs) if row_id and not _is_uuid(row_id)
|
|
600
|
+
]
|
|
601
|
+
if bad:
|
|
602
|
+
raise serializers.ValidationError(
|
|
603
|
+
{"id": f"Row ids must be valid UUIDs; got: {', '.join(bad[:5])}."}
|
|
604
|
+
)
|
|
605
|
+
return attrs
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
class SyncUploadChangesSerializer(serializers.Serializer): # type: ignore[type-arg]
|
|
609
|
+
"""The ``changes`` map of an upload envelope, keyed by collection name.
|
|
610
|
+
|
|
611
|
+
v1 exposes only the writable ``tasks`` collection (ADR-0082 §B); every other
|
|
612
|
+
collection is pull-only. Unsupported collection keys are **not** rejected
|
|
613
|
+
here — ``apply_task_changes`` is the single authority for the writable-
|
|
614
|
+
collection whitelist and rejects them with an explicit 400 (rather than
|
|
615
|
+
silently dropping them). This serializer therefore documents the writable
|
|
616
|
+
shape in the OpenAPI schema without masking that guard; the view feeds the
|
|
617
|
+
raw ``changes`` map to ``apply_task_changes`` so behavior stays identical.
|
|
618
|
+
"""
|
|
619
|
+
|
|
620
|
+
tasks = SyncUploadCollectionSerializer(required=False)
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
class SyncUploadRequestSerializer(serializers.Serializer): # type: ignore[type-arg]
|
|
624
|
+
"""Validate the envelope of a mobile upload batch (ADR-0082 §A).
|
|
625
|
+
|
|
626
|
+
``changes`` is a typed nested map (per-collection created/updated/deleted
|
|
627
|
+
lists) so the WatermelonDB upload shape is explicit in the OpenAPI schema and
|
|
628
|
+
the generated web types, instead of the opaque object it was before (#786).
|
|
629
|
+
Per-collection row validation still happens in ``sync.upload`` so an
|
|
630
|
+
unsupported collection can be rejected with an explicit 400 rather than
|
|
631
|
+
silently dropped. ``last_pulled_at`` is the client's last-pull high-water mark
|
|
632
|
+
and is the default per-row base version for the field-level conflict guard
|
|
633
|
+
(#1718): a stale edit that overlaps a concurrent writer is reported in the
|
|
634
|
+
response ``conflicts`` collection instead of silently clobbering. Omit it (and
|
|
635
|
+
any per-row ``base_version``) to keep plain last-writer-wins.
|
|
636
|
+
"""
|
|
637
|
+
|
|
638
|
+
client_batch_id = serializers.UUIDField()
|
|
639
|
+
last_pulled_at = serializers.IntegerField(required=False, min_value=0)
|
|
640
|
+
changes = SyncUploadChangesSerializer()
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
class SyncUploadAppliedTasksSerializer(serializers.Serializer): # type: ignore[type-arg]
|
|
644
|
+
"""The ``applied.tasks`` bucket of an upload response — rows actually written.
|
|
645
|
+
|
|
646
|
+
Mirrors :class:`SyncUploadCollectionSerializer`'s shape (created/updated as
|
|
647
|
+
full row objects, deleted as row dicts too — the view echoes back the applied
|
|
648
|
+
content rather than just ids). Row objects are deliberately free-form
|
|
649
|
+
(``DictField``), same rationale as the request-side collection serializer:
|
|
650
|
+
the row shape is whatever ``TaskSerializer`` produced inside ``sync.upload``,
|
|
651
|
+
not re-declared here (#3652/#3681).
|
|
652
|
+
"""
|
|
653
|
+
|
|
654
|
+
created = serializers.ListField(child=serializers.DictField(), read_only=True)
|
|
655
|
+
updated = serializers.ListField(child=serializers.DictField(), read_only=True)
|
|
656
|
+
deleted = serializers.ListField(child=serializers.DictField(), read_only=True)
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
class SyncUploadAppliedSerializer(serializers.Serializer): # type: ignore[type-arg]
|
|
660
|
+
"""The ``applied`` envelope of an upload response, keyed by collection name."""
|
|
661
|
+
|
|
662
|
+
tasks = SyncUploadAppliedTasksSerializer(read_only=True)
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
class SyncUploadConflictsSerializer(serializers.Serializer): # type: ignore[type-arg]
|
|
666
|
+
"""The ``conflicts`` envelope of an upload response, keyed by collection name.
|
|
667
|
+
|
|
668
|
+
Each entry is the REST-parity 409 body (``conflict_fields`` / ``server_value``
|
|
669
|
+
/ ``client_value`` / ``server_version``) plus the row ``id`` — free-form here
|
|
670
|
+
for the same reason as the applied-row buckets above.
|
|
671
|
+
"""
|
|
672
|
+
|
|
673
|
+
tasks = serializers.ListField(child=serializers.DictField(), read_only=True)
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
class SyncUploadResponseSerializer(serializers.Serializer): # type: ignore[type-arg]
|
|
677
|
+
"""``200`` body of ``POST /api/v1/projects/{pk}/sync/`` (ADR-0082 §D, #3681).
|
|
678
|
+
|
|
679
|
+
``client_batch_id`` echoes the request so a client can correlate a fast-path
|
|
680
|
+
replay with the original submission. ``timestamp`` is the batch's high-water
|
|
681
|
+
``sync_seq`` cursor (see :class:`BatchApplyResult.max_version`) — adopt it as
|
|
682
|
+
the next pull's ``since`` once conflicts (if any) are resolved.
|
|
683
|
+
"""
|
|
684
|
+
|
|
685
|
+
client_batch_id = serializers.CharField(read_only=True)
|
|
686
|
+
applied = SyncUploadAppliedSerializer(read_only=True)
|
|
687
|
+
conflicts = SyncUploadConflictsSerializer(read_only=True)
|
|
688
|
+
timestamp = serializers.IntegerField(read_only=True)
|