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,171 @@
|
|
|
1
|
+
"""Signals for the access app — real-time eviction on membership revocation (#813).
|
|
2
|
+
|
|
3
|
+
The project WebSocket consumer checks ``ProjectMembership`` only at
|
|
4
|
+
``websocket_connect``. Once accepted, a socket keeps receiving project events until it
|
|
5
|
+
disconnects, so a user whose membership is soft-deleted or demoted below ``Role.MEMBER``
|
|
6
|
+
would keep receiving real-time CPM/task/presence data for as long as the socket stayed
|
|
7
|
+
open — the active-connection analog of #419 (which fixed the reconnect-time path).
|
|
8
|
+
|
|
9
|
+
These signals detect a revocation transition on any ``ProjectMembership`` write — the
|
|
10
|
+
viewset, the ownership-transfer service, and the workspace Group→project cascade all go
|
|
11
|
+
through ``save()``/``delete()`` — and push a ``connection.evict`` to the project's WS
|
|
12
|
+
groups so the affected user's live sockets close with code 4003 immediately.
|
|
13
|
+
|
|
14
|
+
**Account deactivation is a second, independent revocation axis (#2850).** Workspace
|
|
15
|
+
off-boarding writes ``WorkspaceMembership.status = DEACTIVATED`` and
|
|
16
|
+
``User.is_active = False`` and **never touches ``ProjectMembership``**, so the
|
|
17
|
+
membership receivers below never fired for it. Two prior fixes each closed one axis
|
|
18
|
+
and neither closed the intersection: #813 closed revoke-while-connected for *project
|
|
19
|
+
membership*, #888 closed the ``is_active`` gap at *connect time* — leaving an
|
|
20
|
+
off-boarded member's already-open socket streaming until they closed the tab.
|
|
21
|
+
|
|
22
|
+
The account-level receiver is bound to ``User`` rather than added as two calls in the
|
|
23
|
+
off-boarding view precisely because that is what makes it cover the *class*: both
|
|
24
|
+
off-boarding branches, the Django admin, a management command, and any future
|
|
25
|
+
deactivation path all go through ``User.save()``.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
from functools import partial
|
|
31
|
+
from typing import Any
|
|
32
|
+
|
|
33
|
+
from django.conf import settings
|
|
34
|
+
from django.db import transaction
|
|
35
|
+
from django.db.models.signals import post_delete, pre_save
|
|
36
|
+
from django.dispatch import receiver
|
|
37
|
+
|
|
38
|
+
from trueppm_api.apps.access.models import ProjectMembership, Role
|
|
39
|
+
from trueppm_api.apps.access.permissions import role_can_subscribe_live
|
|
40
|
+
from trueppm_api.apps.sync.broadcast import evict_project_connection
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _schedule_evict(project_id: Any, user_id: Any) -> None:
|
|
44
|
+
"""Defer the evict to commit so a rolled-back revocation evicts nobody."""
|
|
45
|
+
transaction.on_commit(partial(evict_project_connection, str(project_id), str(user_id)))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def evict_all_live_project_sockets(user_id: Any) -> None:
|
|
49
|
+
"""Schedule an evict for every project ``user_id`` holds a live membership in.
|
|
50
|
+
|
|
51
|
+
Shared by :func:`_evict_on_account_deactivation` and the password-reset confirm
|
|
52
|
+
view (#4462) — both revoke all of a user's standing authority in one stroke and
|
|
53
|
+
must close the same set of sockets a membership-by-membership revoke would
|
|
54
|
+
eventually reach. Live memberships only: a soft-deleted one already evicted via
|
|
55
|
+
:func:`_evict_on_revocation`, and the consumer would refuse the reconnect anyway.
|
|
56
|
+
"""
|
|
57
|
+
project_ids = ProjectMembership.objects.filter(user_id=user_id, is_deleted=False).values_list(
|
|
58
|
+
"project_id", flat=True
|
|
59
|
+
)
|
|
60
|
+
for project_id in project_ids:
|
|
61
|
+
_schedule_evict(project_id, user_id)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _discard_active_timers_on_revocation(project_id: Any, user_id: Any) -> None:
|
|
65
|
+
"""Delete the user's running timer(s) on this project's tasks (#4318).
|
|
66
|
+
|
|
67
|
+
**Discard, not finalize — the settled choice for #4318.** A member whose
|
|
68
|
+
``ProjectMembership`` is revoked (removed, or demoted below ``Role.MEMBER``, so
|
|
69
|
+
``can_log_time`` would now answer ``False``) can still have a live
|
|
70
|
+
``ActiveTimer`` row ticking. Two options existed: auto-finalize it into a
|
|
71
|
+
``TimeEntry`` at the moment of revocation, or drop it with no entry created.
|
|
72
|
+
Discard was chosen — auto-finalizing would silently attribute logged hours to a
|
|
73
|
+
project the user no longer belongs to, and the resulting entry would outlive
|
|
74
|
+
the membership that was supposed to authorize it. A dropped timer is simply
|
|
75
|
+
gone; a subsequent ``POST /me/timer/stop`` finds no row and answers the
|
|
76
|
+
existing ``409`` ("no active timer to stop"), not a new error shape.
|
|
77
|
+
|
|
78
|
+
Synchronous, inside the caller's transaction — unlike ``_schedule_evict``, this
|
|
79
|
+
is a same-database write with no external side effect, so it naturally rolls
|
|
80
|
+
back together with the membership change on a failed transaction; deferring it
|
|
81
|
+
to commit would buy nothing and would let a stopped-in-between request race the
|
|
82
|
+
delete.
|
|
83
|
+
|
|
84
|
+
Scoped to ``project_id`` (not every project the user belongs to): a revocation
|
|
85
|
+
on one project must not touch a running timer on another project the user is
|
|
86
|
+
still a live member of.
|
|
87
|
+
"""
|
|
88
|
+
from trueppm_api.apps.timetracking.models import ActiveTimer
|
|
89
|
+
|
|
90
|
+
ActiveTimer.objects.filter(user_id=user_id, task__project_id=project_id).delete()
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@receiver(pre_save, sender=ProjectMembership, dispatch_uid="access_evict_on_membership_revocation")
|
|
94
|
+
def _evict_on_revocation(sender: type, instance: ProjectMembership, **kwargs: Any) -> None:
|
|
95
|
+
"""Evict live sockets and discard running timers when a membership is revoked.
|
|
96
|
+
|
|
97
|
+
Two independent checks, both also triggered by a soft-delete. Eviction fires
|
|
98
|
+
when the role stops clearing ``role_can_subscribe_live`` (the socket's own
|
|
99
|
+
connect floor, #4375). Timer discard fires on a demotion across the Member
|
|
100
|
+
time-logging floor. The two floors coincide today (Member), so e.g.
|
|
101
|
+
Admin -> Viewer triggers both and Admin -> Member triggers neither, but they
|
|
102
|
+
are separate rules and moving one must not move the other. See
|
|
103
|
+
:func:`_discard_active_timers_on_revocation` for why the timer is discarded
|
|
104
|
+
rather than finalized (#4318).
|
|
105
|
+
"""
|
|
106
|
+
if instance.pk is None:
|
|
107
|
+
return # brand-new membership — nothing to revoke
|
|
108
|
+
old = ProjectMembership.objects.filter(pk=instance.pk).only("role", "is_deleted").first()
|
|
109
|
+
if old is None:
|
|
110
|
+
return
|
|
111
|
+
became_deleted = not old.is_deleted and instance.is_deleted
|
|
112
|
+
# Eviction keys on the socket's OWN floor — the predicate the consumer's connect
|
|
113
|
+
# gate calls — so a socket is evicted exactly when a fresh connect would be
|
|
114
|
+
# refused, wherever that floor sits (#4375). An inline ordinal comparison here
|
|
115
|
+
# would drift silently if the floor moved.
|
|
116
|
+
lost_live_updates = role_can_subscribe_live(old.role) and not role_can_subscribe_live(
|
|
117
|
+
instance.role
|
|
118
|
+
)
|
|
119
|
+
if became_deleted or lost_live_updates:
|
|
120
|
+
_schedule_evict(instance.project_id, instance.user_id)
|
|
121
|
+
# Timers follow the time-logging floor (Member), a different rule that happens to
|
|
122
|
+
# share today's ordinal; keep it separate so moving one floor does not move the
|
|
123
|
+
# other. A demotion that stays at or above Member keeps the user able to log time.
|
|
124
|
+
demoted_below_member = old.role >= Role.MEMBER and instance.role < Role.MEMBER
|
|
125
|
+
if became_deleted or demoted_below_member:
|
|
126
|
+
_discard_active_timers_on_revocation(instance.project_id, instance.user_id)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@receiver(
|
|
130
|
+
post_delete, sender=ProjectMembership, dispatch_uid="access_evict_on_membership_hard_delete"
|
|
131
|
+
)
|
|
132
|
+
def _evict_on_hard_delete(sender: type, instance: ProjectMembership, **kwargs: Any) -> None:
|
|
133
|
+
"""Evict live sockets and discard running timers if a membership row is hard-deleted.
|
|
134
|
+
|
|
135
|
+
Cascade / admin only — the viewset's own removal path soft-deletes (see
|
|
136
|
+
:func:`_evict_on_revocation`). A cascaded *project* delete already removes any
|
|
137
|
+
``ActiveTimer`` transitively (``Task`` -> ``Project`` is ``CASCADE``), so this
|
|
138
|
+
mainly covers a direct admin hard-delete of just the membership row, where the
|
|
139
|
+
project and its tasks are untouched (#4318).
|
|
140
|
+
"""
|
|
141
|
+
_schedule_evict(instance.project_id, instance.user_id)
|
|
142
|
+
_discard_active_timers_on_revocation(instance.project_id, instance.user_id)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@receiver(pre_save, sender=settings.AUTH_USER_MODEL, dispatch_uid="access_evict_on_deactivation")
|
|
146
|
+
def _evict_on_account_deactivation(sender: type, instance: Any, **kwargs: Any) -> None:
|
|
147
|
+
"""Evict every live project socket when an account is deactivated (#2850).
|
|
148
|
+
|
|
149
|
+
Authorization on both consumers runs exactly once, at connect, and ``is_active``
|
|
150
|
+
is read only there (``sync/ws_auth.py:_resolve_active_user``). So an off-boarded
|
|
151
|
+
member's open socket kept streaming ``task_created`` / ``task_dates_updated`` /
|
|
152
|
+
presence for the whole session — while their REST access died immediately,
|
|
153
|
+
because the JWT authenticator does honor ``is_active``.
|
|
154
|
+
|
|
155
|
+
Fires on the ``True -> False`` transition only. Reactivation grants nothing that
|
|
156
|
+
needs evicting, and firing on every ``User.save()`` would push an evict message
|
|
157
|
+
per project on unrelated profile edits.
|
|
158
|
+
|
|
159
|
+
Deferred to commit through ``_schedule_evict``, so a rolled-back deactivation
|
|
160
|
+
evicts nobody — the same contract the membership receivers above use.
|
|
161
|
+
"""
|
|
162
|
+
if instance.pk is None:
|
|
163
|
+
return # new account — nothing connected under it yet
|
|
164
|
+
if instance.is_active:
|
|
165
|
+
return # not a deactivation; reactivation needs no evict
|
|
166
|
+
model = type(instance)
|
|
167
|
+
was_active = model.objects.filter(pk=instance.pk).values_list("is_active", flat=True).first()
|
|
168
|
+
if not was_active:
|
|
169
|
+
return # already inactive — an unrelated save, not the transition
|
|
170
|
+
|
|
171
|
+
evict_all_live_project_sockets(instance.pk)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Celery tasks for the access app — JWT blacklist maintenance (#910)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from django.apps import apps as django_apps
|
|
9
|
+
from django.core.management import call_command
|
|
10
|
+
from django.db import OperationalError
|
|
11
|
+
|
|
12
|
+
from trueppm_api.core.idempotent import idempotent_task
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
_BLACKLIST_APP = "rest_framework_simplejwt.token_blacklist"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@idempotent_task(
|
|
20
|
+
lock_key_template="flush_expired_blacklisted_tokens",
|
|
21
|
+
lock_ttl=300,
|
|
22
|
+
on_contention="skip",
|
|
23
|
+
name="access.flush_expired_blacklisted_tokens",
|
|
24
|
+
autoretry_for=(ConnectionError, OperationalError),
|
|
25
|
+
retry_backoff=60,
|
|
26
|
+
retry_backoff_max=600,
|
|
27
|
+
retry_jitter=True,
|
|
28
|
+
max_retries=3,
|
|
29
|
+
soft_time_limit=120,
|
|
30
|
+
time_limit=180,
|
|
31
|
+
acks_late=True,
|
|
32
|
+
)
|
|
33
|
+
def flush_expired_blacklisted_tokens(self: object) -> dict[str, Any]:
|
|
34
|
+
"""Delete OutstandingToken/BlacklistedToken rows whose tokens have expired.
|
|
35
|
+
|
|
36
|
+
Registered in CELERY_BEAT_SCHEDULE to run nightly. Without it the blacklist
|
|
37
|
+
tables grow by one OutstandingToken per login for the life of the deployment;
|
|
38
|
+
flushing expired rows bounds them to roughly the active-session window.
|
|
39
|
+
|
|
40
|
+
Wraps simplejwt's ``flushexpiredtokens`` management command. No-ops when the
|
|
41
|
+
``token_blacklist`` app is not installed (the lean-OSS opt-out described in
|
|
42
|
+
settings.SIMPLE_JWT) so the beat schedule entry is safe to ship unconditionally.
|
|
43
|
+
"""
|
|
44
|
+
if not django_apps.is_installed(_BLACKLIST_APP):
|
|
45
|
+
logger.info("flush_expired_blacklisted_tokens: token_blacklist not installed, skipping")
|
|
46
|
+
return {"status": "skipped", "reason": "token_blacklist app not installed"}
|
|
47
|
+
|
|
48
|
+
call_command("flushexpiredtokens")
|
|
49
|
+
logger.info("flush_expired_blacklisted_tokens: flushed expired blacklist rows")
|
|
50
|
+
return {"status": "ok"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""Per-token rate limits for the MCP read surface (ADR-0186, #1808 finding F4).
|
|
2
|
+
|
|
3
|
+
Every view mixing in
|
|
4
|
+
:class:`~trueppm_api.apps.access.permissions.McpReadableViewMixin` is additively
|
|
5
|
+
reachable by a personal ``mcp:read`` API token. Those token-authenticated reads
|
|
6
|
+
had no rate bound: an agent retry loop — or a hostile client holding a leaked
|
|
7
|
+
read-only token — could hammer the surface, and the compute-heavy tools
|
|
8
|
+
(``whatif``, ``monte-carlo/latest``, ``forecast``, ``sprint-forecast``) each
|
|
9
|
+
trigger a CPM + Monte Carlo recompute per call, so an unbounded loop burns
|
|
10
|
+
arbitrary CPU on a read-only credential.
|
|
11
|
+
|
|
12
|
+
Two throttles bound the *token* caller only. :meth:`get_cache_key` returns
|
|
13
|
+
``None`` for any non-token (human JWT/Session) request, which DRF treats as "not
|
|
14
|
+
throttled" — so interactive human traffic on the same views is unaffected
|
|
15
|
+
(#1808 scope: do not throttle human/session traffic). This is the OSS seed of the
|
|
16
|
+
Phase-4 per-agent budget work; per-agent budgets and anomaly auto-suspend remain
|
|
17
|
+
Enterprise.
|
|
18
|
+
|
|
19
|
+
Keyed on the token's own id (not the owner user) so each minted token carries its
|
|
20
|
+
own bucket: revoking or re-minting a token starts a fresh window, and two agents
|
|
21
|
+
holding two distinct tokens neither share nor starve one budget.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from typing import TYPE_CHECKING
|
|
27
|
+
|
|
28
|
+
from rest_framework.throttling import SimpleRateThrottle
|
|
29
|
+
|
|
30
|
+
if TYPE_CHECKING:
|
|
31
|
+
from rest_framework.request import Request
|
|
32
|
+
from rest_framework.views import APIView
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class _McpTokenThrottle(SimpleRateThrottle):
|
|
36
|
+
"""Base: throttle a request only when it is authenticated by an *agent* token.
|
|
37
|
+
|
|
38
|
+
A non-token caller (human JWT/Session) yields ``None`` from
|
|
39
|
+
:meth:`get_cache_key`, which DRF interprets as "skip this throttle entirely",
|
|
40
|
+
so the baseline ``user``/scoped throttles remain the only bound on human
|
|
41
|
+
traffic. An agent-token caller is bucketed on the token's own primary key.
|
|
42
|
+
|
|
43
|
+
A ``legacy:full`` personal access token also yields ``None`` (#2877). These are
|
|
44
|
+
*agent* budgets: ``mcp_read`` is 120/min and ``mcp_read_compute`` 12/min, against
|
|
45
|
+
1000/min on the ``user`` scope a session gets. Metering a person's own CI script
|
|
46
|
+
from the agent bucket capped it 8× tighter than the same person's browser — and
|
|
47
|
+
since ``get_throttles`` is method-agnostic, once #2877 let that token write, its
|
|
48
|
+
*writes* were being metered by a bucket named and sized for agent reads. Falling
|
|
49
|
+
through to the ``user`` scope keeps it bounded and keeps the promise that a PAT is
|
|
50
|
+
"governed exactly as your own session would be."
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
def get_cache_key(self, request: Request, view: APIView) -> str | None:
|
|
54
|
+
# Local import: the model layer is not import-safe at settings-load time.
|
|
55
|
+
from trueppm_api.apps.projects.models import is_agent_token
|
|
56
|
+
|
|
57
|
+
token = getattr(request, "auth", None)
|
|
58
|
+
if is_agent_token(token):
|
|
59
|
+
return self.cache_format % {"scope": self.scope, "ident": str(token.pk)}
|
|
60
|
+
return None # human, or the owner's own full-access PAT — not an agent
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class McpTokenReadThrottle(_McpTokenThrottle):
|
|
64
|
+
"""Baseline per-token cap applied across the whole MCP read surface."""
|
|
65
|
+
|
|
66
|
+
scope = "mcp_read"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class McpTokenComputeThrottle(_McpTokenThrottle):
|
|
70
|
+
"""Tighter per-token cap for the compute-heavy MCP tools.
|
|
71
|
+
|
|
72
|
+
Stacked on top of :class:`McpTokenReadThrottle` for the reads that trigger a
|
|
73
|
+
CPM or Monte Carlo recompute per call — whatif, monte-carlo/latest, forecast,
|
|
74
|
+
sprint-forecast, schedule derivation, and the program schedule action
|
|
75
|
+
(``mcp_compute_heavy`` / ``mcp_compute_heavy_actions``) — so a token loop that
|
|
76
|
+
could burn CPU is bounded well below the baseline read rate.
|
|
77
|
+
|
|
78
|
+
Unlike its base class, this one applies to **every** ``ApiToken`` regardless of
|
|
79
|
+
scope (#2877). The distinction is what each cap is *for*: ``mcp_read`` is an agent
|
|
80
|
+
budget, and metering a person's own CI script from it capped them 8× tighter than
|
|
81
|
+
their own browser. This cap is CPU protection, and CPU does not care which
|
|
82
|
+
credential class asked — an unattended loop against a Monte Carlo recompute is
|
|
83
|
+
equally expensive from a ``legacy:full`` script. Twelve recomputes a minute is far
|
|
84
|
+
above what any real automation needs (a nightly export reads each forecast once),
|
|
85
|
+
so keeping it credential-agnostic costs the legitimate case nothing.
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
scope = "mcp_read_compute"
|
|
89
|
+
|
|
90
|
+
def get_cache_key(self, request: Request, view: APIView) -> str | None:
|
|
91
|
+
from trueppm_api.apps.projects.models import ApiToken
|
|
92
|
+
|
|
93
|
+
token = getattr(request, "auth", None)
|
|
94
|
+
if isinstance(token, ApiToken):
|
|
95
|
+
return self.cache_format % {"scope": self.scope, "ident": str(token.pk)}
|
|
96
|
+
return None # human JWT/Session — bounded by the account-level throttle
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"""URL routing for the access app."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from django.urls import path
|
|
6
|
+
|
|
7
|
+
from trueppm_api.apps.access.views import (
|
|
8
|
+
ExternalStakeholderViewSet,
|
|
9
|
+
MeView,
|
|
10
|
+
ProgramMembershipViewSet,
|
|
11
|
+
ProgramUserDefinedMentionGroupViewSet,
|
|
12
|
+
ProjectMembershipViewSet,
|
|
13
|
+
UserDefinedMentionGroupViewSet,
|
|
14
|
+
UserSearchView,
|
|
15
|
+
)
|
|
16
|
+
from trueppm_api.apps.profiles.views import MyPinnedView, MyProfileView
|
|
17
|
+
|
|
18
|
+
_members = ProjectMembershipViewSet.as_view(
|
|
19
|
+
{
|
|
20
|
+
"get": "list",
|
|
21
|
+
"post": "create",
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
_member_detail = ProjectMembershipViewSet.as_view(
|
|
25
|
+
{
|
|
26
|
+
"get": "retrieve",
|
|
27
|
+
"patch": "partial_update",
|
|
28
|
+
"delete": "destroy",
|
|
29
|
+
}
|
|
30
|
+
)
|
|
31
|
+
_program_members = ProgramMembershipViewSet.as_view(
|
|
32
|
+
{
|
|
33
|
+
"get": "list",
|
|
34
|
+
"post": "create",
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
_program_member_detail = ProgramMembershipViewSet.as_view(
|
|
38
|
+
{
|
|
39
|
+
"get": "retrieve",
|
|
40
|
+
"patch": "partial_update",
|
|
41
|
+
"delete": "destroy",
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
_mention_groups = UserDefinedMentionGroupViewSet.as_view(
|
|
45
|
+
{
|
|
46
|
+
"get": "list",
|
|
47
|
+
"post": "create",
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
_mention_group_detail = UserDefinedMentionGroupViewSet.as_view(
|
|
51
|
+
{
|
|
52
|
+
"get": "retrieve",
|
|
53
|
+
"patch": "partial_update",
|
|
54
|
+
"delete": "destroy",
|
|
55
|
+
}
|
|
56
|
+
)
|
|
57
|
+
_mention_group_add_member = UserDefinedMentionGroupViewSet.as_view({"post": "add_member"})
|
|
58
|
+
_mention_group_remove_member = UserDefinedMentionGroupViewSet.as_view({"post": "remove_member"})
|
|
59
|
+
_mention_group_mute = UserDefinedMentionGroupViewSet.as_view({"post": "mute"})
|
|
60
|
+
_mention_group_unmute = UserDefinedMentionGroupViewSet.as_view({"post": "unmute"})
|
|
61
|
+
_program_mention_groups = ProgramUserDefinedMentionGroupViewSet.as_view(
|
|
62
|
+
{
|
|
63
|
+
"get": "list",
|
|
64
|
+
"post": "create",
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
_program_mention_group_detail = ProgramUserDefinedMentionGroupViewSet.as_view(
|
|
68
|
+
{
|
|
69
|
+
"get": "retrieve",
|
|
70
|
+
"patch": "partial_update",
|
|
71
|
+
"delete": "destroy",
|
|
72
|
+
}
|
|
73
|
+
)
|
|
74
|
+
_program_mention_group_add_member = ProgramUserDefinedMentionGroupViewSet.as_view(
|
|
75
|
+
{"post": "add_member"}
|
|
76
|
+
)
|
|
77
|
+
_program_mention_group_remove_member = ProgramUserDefinedMentionGroupViewSet.as_view(
|
|
78
|
+
{"post": "remove_member"}
|
|
79
|
+
)
|
|
80
|
+
_program_mention_group_mute = ProgramUserDefinedMentionGroupViewSet.as_view({"post": "mute"})
|
|
81
|
+
_program_mention_group_unmute = ProgramUserDefinedMentionGroupViewSet.as_view({"post": "unmute"})
|
|
82
|
+
_program_external_stakeholders = ExternalStakeholderViewSet.as_view(
|
|
83
|
+
{
|
|
84
|
+
"get": "list",
|
|
85
|
+
"post": "create",
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
_program_external_stakeholder_detail = ExternalStakeholderViewSet.as_view(
|
|
89
|
+
{
|
|
90
|
+
"get": "retrieve",
|
|
91
|
+
"patch": "partial_update",
|
|
92
|
+
"delete": "destroy",
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
urlpatterns = [
|
|
97
|
+
path("auth/me/", MeView.as_view(), name="auth-me"),
|
|
98
|
+
path("auth/me/profile/", MyProfileView.as_view(), name="auth-me-profile"),
|
|
99
|
+
path("auth/me/pinned/", MyPinnedView.as_view(), name="auth-me-pinned"),
|
|
100
|
+
path("users/search/", UserSearchView.as_view(), name="user-search"),
|
|
101
|
+
path(
|
|
102
|
+
"projects/<uuid:project_pk>/members/",
|
|
103
|
+
_members,
|
|
104
|
+
name="project-members-list",
|
|
105
|
+
),
|
|
106
|
+
path(
|
|
107
|
+
"projects/<uuid:project_pk>/members/<uuid:pk>/",
|
|
108
|
+
_member_detail,
|
|
109
|
+
name="project-members-detail",
|
|
110
|
+
),
|
|
111
|
+
path(
|
|
112
|
+
"programs/<uuid:program_pk>/members/",
|
|
113
|
+
_program_members,
|
|
114
|
+
name="program-members-list",
|
|
115
|
+
),
|
|
116
|
+
path(
|
|
117
|
+
"programs/<uuid:program_pk>/members/<uuid:pk>/",
|
|
118
|
+
_program_member_detail,
|
|
119
|
+
name="program-members-detail",
|
|
120
|
+
),
|
|
121
|
+
path(
|
|
122
|
+
"projects/<uuid:project_pk>/mention-groups/",
|
|
123
|
+
_mention_groups,
|
|
124
|
+
name="project-mention-groups-list",
|
|
125
|
+
),
|
|
126
|
+
path(
|
|
127
|
+
"projects/<uuid:project_pk>/mention-groups/<uuid:pk>/",
|
|
128
|
+
_mention_group_detail,
|
|
129
|
+
name="project-mention-groups-detail",
|
|
130
|
+
),
|
|
131
|
+
path(
|
|
132
|
+
"projects/<uuid:project_pk>/mention-groups/<uuid:pk>/add-member/",
|
|
133
|
+
_mention_group_add_member,
|
|
134
|
+
name="project-mention-groups-add-member",
|
|
135
|
+
),
|
|
136
|
+
path(
|
|
137
|
+
"projects/<uuid:project_pk>/mention-groups/<uuid:pk>/remove-member/",
|
|
138
|
+
_mention_group_remove_member,
|
|
139
|
+
name="project-mention-groups-remove-member",
|
|
140
|
+
),
|
|
141
|
+
path(
|
|
142
|
+
"projects/<uuid:project_pk>/mention-groups/<uuid:pk>/mute/",
|
|
143
|
+
_mention_group_mute,
|
|
144
|
+
name="project-mention-groups-mute",
|
|
145
|
+
),
|
|
146
|
+
path(
|
|
147
|
+
"projects/<uuid:project_pk>/mention-groups/<uuid:pk>/unmute/",
|
|
148
|
+
_mention_group_unmute,
|
|
149
|
+
name="project-mention-groups-unmute",
|
|
150
|
+
),
|
|
151
|
+
path(
|
|
152
|
+
"programs/<uuid:program_pk>/mention-groups/",
|
|
153
|
+
_program_mention_groups,
|
|
154
|
+
name="program-mention-groups-list",
|
|
155
|
+
),
|
|
156
|
+
path(
|
|
157
|
+
"programs/<uuid:program_pk>/mention-groups/<uuid:pk>/",
|
|
158
|
+
_program_mention_group_detail,
|
|
159
|
+
name="program-mention-groups-detail",
|
|
160
|
+
),
|
|
161
|
+
path(
|
|
162
|
+
"programs/<uuid:program_pk>/mention-groups/<uuid:pk>/add-member/",
|
|
163
|
+
_program_mention_group_add_member,
|
|
164
|
+
name="program-mention-groups-add-member",
|
|
165
|
+
),
|
|
166
|
+
path(
|
|
167
|
+
"programs/<uuid:program_pk>/mention-groups/<uuid:pk>/remove-member/",
|
|
168
|
+
_program_mention_group_remove_member,
|
|
169
|
+
name="program-mention-groups-remove-member",
|
|
170
|
+
),
|
|
171
|
+
path(
|
|
172
|
+
"programs/<uuid:program_pk>/mention-groups/<uuid:pk>/mute/",
|
|
173
|
+
_program_mention_group_mute,
|
|
174
|
+
name="program-mention-groups-mute",
|
|
175
|
+
),
|
|
176
|
+
path(
|
|
177
|
+
"programs/<uuid:program_pk>/mention-groups/<uuid:pk>/unmute/",
|
|
178
|
+
_program_mention_group_unmute,
|
|
179
|
+
name="program-mention-groups-unmute",
|
|
180
|
+
),
|
|
181
|
+
path(
|
|
182
|
+
"programs/<uuid:program_pk>/external-stakeholders/",
|
|
183
|
+
_program_external_stakeholders,
|
|
184
|
+
name="program-external-stakeholders-list",
|
|
185
|
+
),
|
|
186
|
+
path(
|
|
187
|
+
"programs/<uuid:program_pk>/external-stakeholders/<uuid:pk>/",
|
|
188
|
+
_program_external_stakeholder_detail,
|
|
189
|
+
name="program-external-stakeholders-detail",
|
|
190
|
+
),
|
|
191
|
+
]
|