trueppm-api 0.4.0b2__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 +14 -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 +164 -0
- trueppm_api/apps/access/management/commands/migrate_locked.py +96 -0
- trueppm_api/apps/access/management/commands/revoke_api_tokens.py +209 -0
- trueppm_api/apps/access/migrations/0001_initial.py +61 -0
- trueppm_api/apps/access/migrations/0001_squashed_0012_programmembership_role_title.py +167 -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_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 +132 -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/models.py +588 -0
- trueppm_api/apps/access/permissions.py +2837 -0
- trueppm_api/apps/access/serializers.py +946 -0
- trueppm_api/apps/access/services.py +667 -0
- trueppm_api/apps/access/signals.py +103 -0
- trueppm_api/apps/access/tasks.py +50 -0
- trueppm_api/apps/access/throttles.py +95 -0
- trueppm_api/apps/access/urls.py +191 -0
- trueppm_api/apps/access/views.py +1931 -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/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 +108 -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/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 +418 -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 +177 -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 +837 -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 +403 -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_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/__init__.py +0 -0
- trueppm_api/apps/integrations/models.py +622 -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 +519 -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 +731 -0
- trueppm_api/apps/integrations/throttles.py +165 -0
- trueppm_api/apps/integrations/urls.py +77 -0
- trueppm_api/apps/integrations/views.py +1106 -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 +277 -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 +500 -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 +1231 -0
- trueppm_api/apps/msproject/serializers.py +136 -0
- trueppm_api/apps/msproject/services.py +58 -0
- trueppm_api/apps/msproject/tasks.py +436 -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 +447 -0
- trueppm_api/apps/notifications/email_backend.py +330 -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 +294 -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_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 +1197 -0
- trueppm_api/apps/notifications/receivers.py +155 -0
- trueppm_api/apps/notifications/schema_migrations.py +56 -0
- trueppm_api/apps/notifications/serializers.py +961 -0
- trueppm_api/apps/notifications/services.py +1451 -0
- trueppm_api/apps/notifications/tasks.py +711 -0
- trueppm_api/apps/notifications/throttles.py +98 -0
- trueppm_api/apps/notifications/urls.py +97 -0
- trueppm_api/apps/notifications/views.py +904 -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 +551 -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 +969 -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 +523 -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_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 +466 -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 +449 -0
- trueppm_api/apps/projects/backfill.py +287 -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 +204 -0
- trueppm_api/apps/projects/config_notice.py +1325 -0
- trueppm_api/apps/projects/custom_field_values.py +266 -0
- trueppm_api/apps/projects/decisions_services.py +93 -0
- trueppm_api/apps/projects/decisions_views.py +94 -0
- trueppm_api/apps/projects/estimation_scale.py +126 -0
- trueppm_api/apps/projects/export_bundle.py +353 -0
- trueppm_api/apps/projects/fixtures/seeds/atlas-platform-launch.json +4256 -0
- trueppm_api/apps/projects/fixtures/seeds/aurora-mobile-app.json +2000 -0
- trueppm_api/apps/projects/fixtures/seeds/bayside-civic-center.json +1825 -0
- trueppm_api/apps/projects/fixtures/seeds/ga-launch.json +1905 -0
- trueppm_api/apps/projects/fixtures/seeds/helios-crm-replacement.json +1409 -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/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 +247 -0
- trueppm_api/apps/projects/management/commands/seed_capacity.py +405 -0
- trueppm_api/apps/projects/management/commands/seed_integration_fixtures.py +178 -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/migrations/0001_initial.py +208 -0
- trueppm_api/apps/projects/migrations/0001_squashed_0094_project_decisions_policy.py +5595 -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 +44 -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 +61 -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 +62 -0
- trueppm_api/apps/projects/migrations/0106_boardsavedview_schema_version.py +20 -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/__init__.py +0 -0
- trueppm_api/apps/projects/models.py +8946 -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 +575 -0
- trueppm_api/apps/projects/program_schedule.py +745 -0
- trueppm_api/apps/projects/program_views.py +3220 -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 +493 -0
- trueppm_api/apps/projects/schemas/seed_v2.json +892 -0
- trueppm_api/apps/projects/seed/__init__.py +61 -0
- trueppm_api/apps/projects/seed/exporter.py +1644 -0
- trueppm_api/apps/projects/seed/forecast_backfill.py +247 -0
- trueppm_api/apps/projects/seed/importer.py +2390 -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 +126 -0
- trueppm_api/apps/projects/seed/replay.py +1691 -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 +1149 -0
- trueppm_api/apps/projects/serializers.py +12310 -0
- trueppm_api/apps/projects/services.py +6966 -0
- trueppm_api/apps/projects/share_serializers.py +132 -0
- trueppm_api/apps/projects/share_services.py +325 -0
- trueppm_api/apps/projects/share_views.py +374 -0
- trueppm_api/apps/projects/sharing_settings.py +187 -0
- trueppm_api/apps/projects/signal_privacy_services.py +909 -0
- trueppm_api/apps/projects/signal_privacy_views.py +476 -0
- trueppm_api/apps/projects/signals.py +132 -0
- trueppm_api/apps/projects/slip_conflict.py +266 -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 +1152 -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 +1917 -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 +258 -0
- trueppm_api/apps/projects/template_views.py +799 -0
- trueppm_api/apps/projects/throttles.py +311 -0
- trueppm_api/apps/projects/urls.py +1011 -0
- trueppm_api/apps/projects/utilization.py +885 -0
- trueppm_api/apps/projects/views.py +20572 -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/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 +1749 -0
- trueppm_api/apps/scheduling/__init__.py +0 -0
- trueppm_api/apps/scheduling/apps.py +153 -0
- trueppm_api/apps/scheduling/calendars.py +119 -0
- trueppm_api/apps/scheduling/deadletter.py +91 -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/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/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/__init__.py +0 -0
- trueppm_api/apps/scheduling/models.py +516 -0
- trueppm_api/apps/scheduling/receivers.py +160 -0
- trueppm_api/apps/scheduling/risk_premium.py +283 -0
- trueppm_api/apps/scheduling/serializers.py +564 -0
- trueppm_api/apps/scheduling/services.py +1182 -0
- trueppm_api/apps/scheduling/signals.py +56 -0
- trueppm_api/apps/scheduling/tasks.py +1984 -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 +2564 -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 +437 -0
- trueppm_api/apps/sso/services.py +1385 -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 +320 -0
- trueppm_api/apps/sync/conflict.py +262 -0
- trueppm_api/apps/sync/consumers.py +471 -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/0004_seed_sync_seq.py +24 -0
- trueppm_api/apps/sync/migrations/0005_program_sync_sequence.py +35 -0
- trueppm_api/apps/sync/migrations/__init__.py +0 -0
- trueppm_api/apps/sync/models.py +225 -0
- trueppm_api/apps/sync/pagination.py +231 -0
- trueppm_api/apps/sync/sequence.py +371 -0
- trueppm_api/apps/sync/serializers.py +687 -0
- trueppm_api/apps/sync/tasks.py +260 -0
- trueppm_api/apps/sync/throttles.py +175 -0
- trueppm_api/apps/sync/upload.py +501 -0
- trueppm_api/apps/sync/urls.py +17 -0
- trueppm_api/apps/sync/views.py +930 -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 +142 -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/__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 +434 -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/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 +117 -0
- trueppm_api/apps/timetracking/urls.py +47 -0
- trueppm_api/apps/timetracking/views.py +526 -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 +144 -0
- trueppm_api/apps/webhooks/migrations/0001_initial.py +146 -0
- trueppm_api/apps/webhooks/migrations/0001_squashed_0007_sprint_lifecycle_events.py +243 -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 +90 -0
- trueppm_api/apps/webhooks/migrations/__init__.py +0 -0
- trueppm_api/apps/webhooks/models.py +372 -0
- trueppm_api/apps/webhooks/serializers.py +318 -0
- trueppm_api/apps/webhooks/tasks.py +663 -0
- trueppm_api/apps/webhooks/urls.py +22 -0
- trueppm_api/apps/webhooks/views.py +383 -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 +368 -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 +242 -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_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 +919 -0
- trueppm_api/apps/workspace/signals.py +37 -0
- trueppm_api/apps/workspace/tasks.py +555 -0
- trueppm_api/apps/workspace/urls.py +113 -0
- trueppm_api/apps/workspace/views.py +1502 -0
- trueppm_api/asgi.py +42 -0
- trueppm_api/celery.py +31 -0
- trueppm_api/core/__init__.py +0 -0
- trueppm_api/core/admin_site.py +206 -0
- trueppm_api/core/auth_views.py +916 -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/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 +949 -0
- trueppm_api/core/password_reset.py +500 -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 +884 -0
- trueppm_api/core/storage_config.py +105 -0
- trueppm_api/core/text_decode.py +168 -0
- trueppm_api/core/throttling.py +344 -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/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 +2455 -0
- trueppm_api/settings/dev.py +273 -0
- trueppm_api/settings/prod.py +228 -0
- trueppm_api/urls.py +153 -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.0b2.dist-info/METADATA +70 -0
- trueppm_api-0.4.0b2.dist-info/RECORD +759 -0
- trueppm_api-0.4.0b2.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
"""Read + undo endpoints for the structural operation ledger (ADR-0880, #2974, #3006).
|
|
2
|
+
|
|
3
|
+
Follows ``batch_operation_views.py``'s shape — read-only over a server-written ledger,
|
|
4
|
+
one ``undo`` POST action — with two deliberate divergences, both argued in ADR-0880:
|
|
5
|
+
|
|
6
|
+
**The list is scoped tighter than its ADR-0810 siblings.** ``PasteManyOperationViewSet``
|
|
7
|
+
scopes to project membership with no role floor, so a Viewer reads it. For the *move*
|
|
8
|
+
dimension that leaks nothing (a Viewer already reads ``GET /tasks/``), but this ledger is
|
|
9
|
+
a *historical* record: ``shape_before`` preserves how the plan was organized before a
|
|
10
|
+
reorg the live tree no longer shows, ``deleted_task_ids`` names tombstoned rows, and
|
|
11
|
+
``applied_by`` + ``created_at`` is a per-member restructure timeline at a finer grain than
|
|
12
|
+
anything a Viewer has today. Scoped to actor-or-Admin, mirroring who can act on it.
|
|
13
|
+
|
|
14
|
+
**Undo is not Admin-gated.** See ``require_structural_undo_authority``.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from typing import Any, cast
|
|
20
|
+
|
|
21
|
+
from django.db.models import Q, QuerySet
|
|
22
|
+
from drf_spectacular.utils import OpenApiResponse, extend_schema, extend_schema_field
|
|
23
|
+
from rest_framework import serializers, status, viewsets
|
|
24
|
+
from rest_framework.decorators import action
|
|
25
|
+
from rest_framework.exceptions import NotFound
|
|
26
|
+
from rest_framework.permissions import IsAuthenticated
|
|
27
|
+
from rest_framework.request import Request
|
|
28
|
+
from rest_framework.response import Response
|
|
29
|
+
|
|
30
|
+
from trueppm_api.apps.access.models import Role
|
|
31
|
+
from trueppm_api.apps.access.permissions import (
|
|
32
|
+
IsProjectMemberWrite,
|
|
33
|
+
IsProjectNotArchived,
|
|
34
|
+
IsProjectPlanAuthor,
|
|
35
|
+
)
|
|
36
|
+
from trueppm_api.apps.idempotency.mixins import IdempotencyMixin
|
|
37
|
+
from trueppm_api.apps.projects.models import Project, StructuralOperation
|
|
38
|
+
from trueppm_api.apps.projects.refusal_codes import StructuralUndoBlockedReason
|
|
39
|
+
from trueppm_api.apps.projects.structural_operation_services import (
|
|
40
|
+
StructuralUndoRejected,
|
|
41
|
+
require_structural_undo_authority,
|
|
42
|
+
undo_blocked_reason,
|
|
43
|
+
undo_structural_operation,
|
|
44
|
+
)
|
|
45
|
+
from trueppm_api.apps.projects.structural_operation_services import (
|
|
46
|
+
may_undo as _may_undo,
|
|
47
|
+
)
|
|
48
|
+
from trueppm_api.core.openapi import undo_summary_schema
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class StructuralOperationSerializer(serializers.ModelSerializer[StructuralOperation]):
|
|
52
|
+
"""The ledger row plus the two computed facts a client needs to render an Undo.
|
|
53
|
+
|
|
54
|
+
``is_undoable`` is a server fact rather than a client derivation on purpose:
|
|
55
|
+
``status`` only answers whether the row has *already* been undone, while undoability
|
|
56
|
+
also varies with live shape, stack position and region size. Without it, an API
|
|
57
|
+
client listing operations sees N rows all reading ``active``, at most one of which is
|
|
58
|
+
actually reversible — and the web trail and that client would each guess separately.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
is_undoable = serializers.SerializerMethodField()
|
|
62
|
+
undo_blocked_reason = serializers.SerializerMethodField()
|
|
63
|
+
|
|
64
|
+
#: Per-serialization memo. DRF calls both method fields for every row, and the
|
|
65
|
+
#: underlying check costs up to five queries — one of which reads the whole
|
|
66
|
+
#: project's live task set on a root-level gesture. Keyed on pk and scoped to this
|
|
67
|
+
#: serializer instance, so it lives exactly as long as one request's page.
|
|
68
|
+
_reason_cache: dict[Any, str]
|
|
69
|
+
|
|
70
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
71
|
+
super().__init__(*args, **kwargs)
|
|
72
|
+
self._reason_cache = {}
|
|
73
|
+
|
|
74
|
+
def _reason(self, obj: StructuralOperation) -> str:
|
|
75
|
+
"""The blocked-reason for this row, computed at most once.
|
|
76
|
+
|
|
77
|
+
Memoized on the instance because DRF calls both method fields, and the
|
|
78
|
+
underlying check costs up to five queries — one of which (`capture_shape` on
|
|
79
|
+
a root-level gesture) reads every live task in the project. Unmemoized, a
|
|
80
|
+
50-row page paid that twice per row.
|
|
81
|
+
|
|
82
|
+
`shape_changed` is deliberately NOT evaluated in a list. It is the expensive
|
|
83
|
+
arm, and it is racy by construction: it can flip between the client reading
|
|
84
|
+
the list and clicking Undo, and the 409 on the write is the authoritative
|
|
85
|
+
answer either way. `retrieve` asks the full question; the list reports the
|
|
86
|
+
three cheap, stable reasons.
|
|
87
|
+
"""
|
|
88
|
+
cached = self._reason_cache.get(obj.pk)
|
|
89
|
+
if cached is None:
|
|
90
|
+
request = self.context.get("request")
|
|
91
|
+
if request is not None and not _may_undo(request, obj):
|
|
92
|
+
cached = StructuralUndoBlockedReason.FORBIDDEN.value
|
|
93
|
+
else:
|
|
94
|
+
cached = undo_blocked_reason(obj, check_shape=bool(self.context.get("detail")))
|
|
95
|
+
self._reason_cache[obj.pk] = cached
|
|
96
|
+
return cached
|
|
97
|
+
|
|
98
|
+
class Meta:
|
|
99
|
+
model = StructuralOperation
|
|
100
|
+
fields = [ # noqa: RUF012
|
|
101
|
+
"id",
|
|
102
|
+
"project",
|
|
103
|
+
"applied_by",
|
|
104
|
+
"undone_by",
|
|
105
|
+
"kind",
|
|
106
|
+
"status",
|
|
107
|
+
"undoable",
|
|
108
|
+
"is_undoable",
|
|
109
|
+
"undo_blocked_reason",
|
|
110
|
+
"result_summary",
|
|
111
|
+
"created_at",
|
|
112
|
+
"undone_at",
|
|
113
|
+
]
|
|
114
|
+
read_only_fields = fields
|
|
115
|
+
|
|
116
|
+
def get_is_undoable(self, obj: StructuralOperation) -> bool:
|
|
117
|
+
return not self._reason(obj)
|
|
118
|
+
|
|
119
|
+
@extend_schema_field(
|
|
120
|
+
serializers.ChoiceField(
|
|
121
|
+
choices=StructuralUndoBlockedReason.choices,
|
|
122
|
+
help_text=(
|
|
123
|
+
"Why this operation cannot be undone, from a closed set (#3037). The "
|
|
124
|
+
"empty string means it can. `shape_changed` is evaluated only on the "
|
|
125
|
+
"detail read — it is racy by construction, and the 409 on the write is "
|
|
126
|
+
"authoritative either way."
|
|
127
|
+
),
|
|
128
|
+
)
|
|
129
|
+
)
|
|
130
|
+
def get_undo_blocked_reason(self, obj: StructuralOperation) -> str:
|
|
131
|
+
return self._reason(obj)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class StructuralOperationUndoSerializer(StructuralOperationSerializer):
|
|
135
|
+
"""The ledger row **plus** the ``undo`` summary the action returns (#3416).
|
|
136
|
+
|
|
137
|
+
``undo`` handler builds its body as ``data = self.get_serializer(operation).data``
|
|
138
|
+
then ``data["undo"] = summary``, so the bare ``StructuralOperationSerializer``
|
|
139
|
+
published as the ``200`` left a typed client with no field for the five counts
|
|
140
|
+
that say what the reversal actually did. Five, not two: a structural undo restores
|
|
141
|
+
shape, un-mints containers, revives tombstoned rows and re-adds dependency edges,
|
|
142
|
+
and it reports each separately because a caller acts on them differently — a
|
|
143
|
+
non-zero ``dependencies_skipped`` in particular means the graph came back
|
|
144
|
+
*incomplete* and the user has edges to re-draw by hand.
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
undo = serializers.SerializerMethodField()
|
|
148
|
+
|
|
149
|
+
class Meta(StructuralOperationSerializer.Meta):
|
|
150
|
+
fields = [*StructuralOperationSerializer.Meta.fields, "undo"] # noqa: RUF012
|
|
151
|
+
|
|
152
|
+
@extend_schema_field(
|
|
153
|
+
undo_summary_schema(
|
|
154
|
+
"What the reversal restored, by kind. All-or-nothing: a refusal is a 409 "
|
|
155
|
+
"with no summary at all, so every count here describes a completed undo.",
|
|
156
|
+
restored="Rows whose parent/order the undo put back.",
|
|
157
|
+
created_removed="Containers the forward act minted and the undo un-minted.",
|
|
158
|
+
deleted_restored="Rows the forward act soft-deleted and the undo revived.",
|
|
159
|
+
dependencies_restored="Dependency edges the undo re-created.",
|
|
160
|
+
dependencies_skipped=(
|
|
161
|
+
"Edges NOT re-created because the other end no longer exists — a "
|
|
162
|
+
"non-zero value means the restored graph is incomplete."
|
|
163
|
+
),
|
|
164
|
+
)
|
|
165
|
+
)
|
|
166
|
+
def get_undo(self, obj: StructuralOperation) -> dict[str, int]:
|
|
167
|
+
"""The persisted summary, for a caller that serializes a row outside the action.
|
|
168
|
+
|
|
169
|
+
The action returns the summary its service just computed rather than this;
|
|
170
|
+
they agree, because ``undo_structural_operation`` persists what it returns.
|
|
171
|
+
"""
|
|
172
|
+
return dict((obj.result_summary or {}).get("undo") or {})
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class StructuralOperationViewSet(
|
|
176
|
+
IdempotencyMixin, viewsets.ReadOnlyModelViewSet[StructuralOperation]
|
|
177
|
+
):
|
|
178
|
+
serializer_class = StructuralOperationSerializer
|
|
179
|
+
# Parity with the six forward endpoints this reverses. `IsProjectNotArchived` is
|
|
180
|
+
# the load-bearing one on this route: without it a Member who indented before
|
|
181
|
+
# archival could still rewrite an archived plan's WBS, resurrect its tombstoned
|
|
182
|
+
# rows and restore its dependency edges — a write no role can otherwise make
|
|
183
|
+
# without unarchiving. `undo_structural_operation` repeats the check at the
|
|
184
|
+
# service layer for callers DRF never sees (#3354).
|
|
185
|
+
# `IsProjectPlanAuthor` matches group/ungroup, keeping the resource-management
|
|
186
|
+
# band excluded from reversing a plan-shaping write as well as making one.
|
|
187
|
+
permission_classes = [ # noqa: RUF012
|
|
188
|
+
IsAuthenticated,
|
|
189
|
+
IsProjectMemberWrite,
|
|
190
|
+
IsProjectPlanAuthor,
|
|
191
|
+
IsProjectNotArchived,
|
|
192
|
+
]
|
|
193
|
+
|
|
194
|
+
def get_serializer_context(self) -> dict[str, Any]:
|
|
195
|
+
context: dict[str, Any] = dict(super().get_serializer_context())
|
|
196
|
+
# Only the detail read pays for the drift comparison (see `undo_blocked_reason`).
|
|
197
|
+
context["detail"] = self.action in {"retrieve", "undo"}
|
|
198
|
+
return context
|
|
199
|
+
|
|
200
|
+
def get_queryset(self) -> QuerySet[StructuralOperation]:
|
|
201
|
+
from trueppm_api.apps.access.models import ProjectMembership
|
|
202
|
+
|
|
203
|
+
memberships = ProjectMembership.objects.filter(
|
|
204
|
+
user=cast("Any", self.request.user), is_deleted=False
|
|
205
|
+
)
|
|
206
|
+
admin_project_ids = list(
|
|
207
|
+
memberships.filter(role__gte=Role.ADMIN).values_list("project_id", flat=True)
|
|
208
|
+
)
|
|
209
|
+
member_project_ids = list(memberships.values_list("project_id", flat=True))
|
|
210
|
+
# Your own acts anywhere you are a member; anyone's acts where you are Admin+.
|
|
211
|
+
# A caller who can neither undo a row nor see it in their own trail has no use
|
|
212
|
+
# for it, and the row is a durable record of structure the live tree no longer
|
|
213
|
+
# shows.
|
|
214
|
+
qs = StructuralOperation.objects.filter(
|
|
215
|
+
Q(project_id__in=member_project_ids, applied_by=cast("Any", self.request.user))
|
|
216
|
+
| Q(project_id__in=admin_project_ids)
|
|
217
|
+
)
|
|
218
|
+
project_id = self.request.query_params.get("project")
|
|
219
|
+
if project_id:
|
|
220
|
+
qs = qs.filter(project_id=project_id)
|
|
221
|
+
return qs
|
|
222
|
+
|
|
223
|
+
@extend_schema(
|
|
224
|
+
request=None,
|
|
225
|
+
responses={
|
|
226
|
+
200: StructuralOperationUndoSerializer,
|
|
227
|
+
409: OpenApiResponse(
|
|
228
|
+
description=(
|
|
229
|
+
"The act can no longer be reversed safely — body is "
|
|
230
|
+
'``{"code": ..., "detail": ..., ...}`` with ``code`` one of '
|
|
231
|
+
"``too_large``, ``not_top_of_stack`` (extra: ``blocking_operation_id``) "
|
|
232
|
+
"or ``shape_changed`` (extra: ``changed``), matching "
|
|
233
|
+
"``StructuralUndoBlockedReason``."
|
|
234
|
+
)
|
|
235
|
+
),
|
|
236
|
+
},
|
|
237
|
+
description=(
|
|
238
|
+
"Reverse this structural act. All-or-nothing: if anything the undo would "
|
|
239
|
+
"write has moved since, it refuses with 409 rather than reverting partially. "
|
|
240
|
+
"Undoing an act you performed needs the same authority the act needed; "
|
|
241
|
+
"undoing someone else's needs Project Manager."
|
|
242
|
+
),
|
|
243
|
+
)
|
|
244
|
+
@action(detail=True, methods=["post"], url_path="undo")
|
|
245
|
+
def undo(self, request: Request, pk: str | None = None) -> Response:
|
|
246
|
+
operation = self.get_object()
|
|
247
|
+
# get_object() runs has_object_permission against the *operation*; the
|
|
248
|
+
# archived/member gates resolve the project off it. Explicit rather than
|
|
249
|
+
# implicit because `_project_pk_from_view` cannot resolve a project from this
|
|
250
|
+
# route's kwargs (there is no `project_pk` segment), so the declarative
|
|
251
|
+
# has_permission pass is non-load-bearing here — the in-body call is what
|
|
252
|
+
# actually enforces it (#2745).
|
|
253
|
+
project = Project.objects.filter(pk=operation.project_id, is_deleted=False).first()
|
|
254
|
+
if project is None:
|
|
255
|
+
raise NotFound("Project not found.")
|
|
256
|
+
self.check_object_permissions(request, project)
|
|
257
|
+
require_structural_undo_authority(request, operation)
|
|
258
|
+
try:
|
|
259
|
+
summary = undo_structural_operation(
|
|
260
|
+
operation,
|
|
261
|
+
undone_by=request.user,
|
|
262
|
+
authorize=_build_authorizer(request),
|
|
263
|
+
)
|
|
264
|
+
except StructuralUndoRejected as rejected:
|
|
265
|
+
return Response(rejected.body, status=status.HTTP_409_CONFLICT)
|
|
266
|
+
operation.refresh_from_db()
|
|
267
|
+
data: dict[str, Any] = self.get_serializer(operation).data
|
|
268
|
+
data["undo"] = summary
|
|
269
|
+
return Response(data, status=status.HTTP_200_OK)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def _build_authorizer(request: Request) -> Any:
|
|
273
|
+
"""Re-check write authority the way the *forward* act did, not more strictly.
|
|
274
|
+
|
|
275
|
+
Two different bars, matching the two things an undo does:
|
|
276
|
+
|
|
277
|
+
``move_rows`` are the rows the forward endpoint itself gated on — the *named* task,
|
|
278
|
+
not the whole region. ``TaskIndentView`` checks the indented row only; its
|
|
279
|
+
descendants and renumbered siblings move unchecked. Gating the region here would be
|
|
280
|
+
stricter than the act being reversed, so a Member who legally indented their own
|
|
281
|
+
assigned task under a phase of colleague-assigned rows could not undo it — exactly
|
|
282
|
+
the asymmetry this design exists to remove, one layer down. Since undo is only
|
|
283
|
+
reachable when the region is byte-identical to what the actor produced, re-checking
|
|
284
|
+
rows the actor never needed authority over buys nothing.
|
|
285
|
+
|
|
286
|
+
``restore_rows`` — rows the act soft-deleted, which undo brings back — are checked
|
|
287
|
+
at DELETE grade, matching what ``perform_ungroup`` uses on the container. The
|
|
288
|
+
default PATCH form admits the Product Owner facet on EPIC/STORY rows regardless of
|
|
289
|
+
assignment; the delete-grade form does not, and deleting is what the forward act
|
|
290
|
+
did to those rows.
|
|
291
|
+
|
|
292
|
+
Rows the act **minted** are deliberately absent. `perform_group` creates its
|
|
293
|
+
container unassigned and requires no delete authority to create it, so requiring
|
|
294
|
+
delete authority to remove it again would deny a Member the reversal of their own
|
|
295
|
+
group. They are covered by ``move_rows``.
|
|
296
|
+
"""
|
|
297
|
+
from rest_framework.exceptions import PermissionDenied
|
|
298
|
+
|
|
299
|
+
from trueppm_api.apps.access.permissions import can_user_edit_task
|
|
300
|
+
from trueppm_api.apps.projects.views import _require_wbs_restructure_permission
|
|
301
|
+
|
|
302
|
+
def authorize(*, move_rows: list[Any], restore_rows: list[Any]) -> None:
|
|
303
|
+
for task in move_rows:
|
|
304
|
+
_require_wbs_restructure_permission(request, task)
|
|
305
|
+
for task in restore_rows:
|
|
306
|
+
if not can_user_edit_task(request, task, method="DELETE"):
|
|
307
|
+
raise PermissionDenied(
|
|
308
|
+
"You do not have permission to reverse this change on this row."
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
return authorize
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""Independent leaf-surface visibility resolution (ADR-0193, issue 956).
|
|
2
|
+
|
|
3
|
+
A project ADMIN can independently hide four *leaf* surfaces — reporting,
|
|
4
|
+
time-tracking, baselines, and the Monte-Carlo surface — from their team's project
|
|
5
|
+
workspace, separately from the methodology preset (which already hides the heavy
|
|
6
|
+
chrome: Gantt/WBS/Sprints/Calendar, ADR-0041/ADR-0107).
|
|
7
|
+
|
|
8
|
+
**Hide-only (ADR-0041):** turning a surface off never disables its endpoint or
|
|
9
|
+
gates its route — the data is always computed and reachable by direct URL. These
|
|
10
|
+
toggles hide chrome; they are a preference, not a permission.
|
|
11
|
+
|
|
12
|
+
**Seeded by methodology, not by parent scope.** Unlike sharing/attachment
|
|
13
|
+
inheritance (project → program → workspace, see ``sharing_settings``), the *default*
|
|
14
|
+
for each surface comes from the project's ``effective_methodology`` via
|
|
15
|
+
``METHODOLOGY_SURFACE_DEFAULTS``. Resolution is therefore two-level and
|
|
16
|
+
computed-on-read (ADR-0108 — no denormalized column):
|
|
17
|
+
|
|
18
|
+
effective(surface) = project.show_<surface> # explicit override
|
|
19
|
+
if project.show_<surface> is not None
|
|
20
|
+
else METHODOLOGY_SURFACE_DEFAULTS[effective_methodology][surface]
|
|
21
|
+
|
|
22
|
+
Clients (web, mobile, MCP) read the serializer's ``effective_surface_visibility``;
|
|
23
|
+
they never re-implement this map. There is no ENFORCE/lock seam — this is a
|
|
24
|
+
per-project preference, not a cross-scope policy, so nothing degrades to SUGGEST
|
|
25
|
+
and no enterprise provider registers against it.
|
|
26
|
+
|
|
27
|
+
**Three of the four keys have a reader; ``time_tracking`` has none** (#3376). That
|
|
28
|
+
sentence above is true for ``reporting`` (the tab filter), ``baselines`` (the task
|
|
29
|
+
drawer's comparison section) and ``monte_carlo`` (the Schedule forecast bar), and
|
|
30
|
+
false for ``time_tracking`` on every client — web and mobile alike. This module
|
|
31
|
+
still resolves all four, and the serializer still serves all four, because the
|
|
32
|
+
column, the methodology default and the API contract are unchanged; what is
|
|
33
|
+
missing is a consumer. An integrator reading ``effective_surface_visibility``
|
|
34
|
+
should treat ``time_tracking`` as a stored preference, not as a statement about
|
|
35
|
+
what any surface will render. See ``Project.show_time_tracking`` and
|
|
36
|
+
``config_notice.ENFORCED_SURFACE_KEYS``.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
from __future__ import annotations
|
|
40
|
+
|
|
41
|
+
from typing import TYPE_CHECKING
|
|
42
|
+
|
|
43
|
+
from trueppm_api.apps.projects.models import Methodology
|
|
44
|
+
|
|
45
|
+
if TYPE_CHECKING:
|
|
46
|
+
from trueppm_api.apps.projects.models import Project
|
|
47
|
+
from trueppm_api.apps.workspace.models import Workspace
|
|
48
|
+
|
|
49
|
+
#: The four independently-toggleable leaf surfaces. The key is the API/serializer
|
|
50
|
+
#: name; the backing column is ``show_<key>`` on ``Project``.
|
|
51
|
+
SURFACE_KEYS: tuple[str, ...] = ("reporting", "time_tracking", "baselines", "monte_carlo")
|
|
52
|
+
|
|
53
|
+
#: Default visibility when a project leaves ``show_<surface>`` NULL (inherit). These
|
|
54
|
+
#: are *floors seeded from the methodology preset*, fully overridable per project
|
|
55
|
+
#: (OSS never clamps — ADR-0135 §5). Baselines and Monte-Carlo default off under
|
|
56
|
+
#: AGILE (CPM/schedule artifacts an agile team rarely surfaces — the issue's own
|
|
57
|
+
#: example); reporting and time-tracking default on everywhere (universally useful).
|
|
58
|
+
METHODOLOGY_SURFACE_DEFAULTS: dict[str, dict[str, bool]] = {
|
|
59
|
+
Methodology.WATERFALL: {
|
|
60
|
+
"reporting": True,
|
|
61
|
+
"time_tracking": True,
|
|
62
|
+
"baselines": True,
|
|
63
|
+
"monte_carlo": True,
|
|
64
|
+
},
|
|
65
|
+
Methodology.AGILE: {
|
|
66
|
+
"reporting": True,
|
|
67
|
+
"time_tracking": True,
|
|
68
|
+
"baselines": False,
|
|
69
|
+
"monte_carlo": False,
|
|
70
|
+
},
|
|
71
|
+
Methodology.HYBRID: {
|
|
72
|
+
"reporting": True,
|
|
73
|
+
"time_tracking": True,
|
|
74
|
+
"baselines": True,
|
|
75
|
+
"monte_carlo": True,
|
|
76
|
+
},
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def methodology_surface_defaults(effective_methodology: str) -> dict[str, bool]:
|
|
81
|
+
"""Default visibility map for a resolved methodology.
|
|
82
|
+
|
|
83
|
+
Falls back to the HYBRID (all-on, lossless) defaults for any unknown value, so
|
|
84
|
+
a future methodology never accidentally hides a surface.
|
|
85
|
+
"""
|
|
86
|
+
return dict(
|
|
87
|
+
METHODOLOGY_SURFACE_DEFAULTS.get(
|
|
88
|
+
effective_methodology, METHODOLOGY_SURFACE_DEFAULTS[Methodology.HYBRID]
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def resolve_effective_visibility(
|
|
94
|
+
project: Project, *, workspace: Workspace | None = None
|
|
95
|
+
) -> dict[str, bool]:
|
|
96
|
+
"""Resolve the effective visibility of every leaf surface for ``project``.
|
|
97
|
+
|
|
98
|
+
Each surface uses the project's explicit override when set, otherwise the
|
|
99
|
+
methodology default. ``workspace`` may be passed to avoid re-loading the
|
|
100
|
+
singleton when resolving a list (the serializer caches it once).
|
|
101
|
+
"""
|
|
102
|
+
from trueppm_api.apps.projects.methodology import resolve_effective_methodology
|
|
103
|
+
|
|
104
|
+
effective_methodology = resolve_effective_methodology(project, workspace=workspace)
|
|
105
|
+
defaults = methodology_surface_defaults(effective_methodology)
|
|
106
|
+
|
|
107
|
+
resolved: dict[str, bool] = {}
|
|
108
|
+
for surface in SURFACE_KEYS:
|
|
109
|
+
override = getattr(project, f"show_{surface}")
|
|
110
|
+
resolved[surface] = bool(override) if override is not None else defaults[surface]
|
|
111
|
+
return resolved
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def resolve_inherited_visibility(
|
|
115
|
+
project: Project, *, workspace: Workspace | None = None
|
|
116
|
+
) -> dict[str, bool]:
|
|
117
|
+
"""Visibility ``project`` would show if every override were cleared.
|
|
118
|
+
|
|
119
|
+
This is exactly the methodology-default map for the project's effective
|
|
120
|
+
methodology — it drives the settings "Inherit (On/Off)" affordance, letting the
|
|
121
|
+
UI show what each toggle falls back to when returned to *inherit*.
|
|
122
|
+
"""
|
|
123
|
+
from trueppm_api.apps.projects.methodology import resolve_effective_methodology
|
|
124
|
+
|
|
125
|
+
effective_methodology = resolve_effective_methodology(project, workspace=workspace)
|
|
126
|
+
return methodology_surface_defaults(effective_methodology)
|