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,119 @@
|
|
|
1
|
+
"""Placing an externally-numbered block of tasks into a project that already has rows.
|
|
2
|
+
|
|
3
|
+
Every document that carries a WBS — a published template, an ``.mpp`` export, a CSV,
|
|
4
|
+
a Jira pull — numbers its tasks from ``1``, because it was written against a project
|
|
5
|
+
that started empty. That is correct exactly once. Writing those paths verbatim into a
|
|
6
|
+
project that already holds rows puts two live tasks on the same ``wbs_path``, and
|
|
7
|
+
``wbs_path`` is the only thing that records parenthood (there is no ``parent_id``
|
|
8
|
+
column), so the collision is not a cosmetic numbering clash — it collapses the next
|
|
9
|
+
``rewrite_level`` pass and strands the subtree underneath.
|
|
10
|
+
|
|
11
|
+
The pair here is the fix for that, and it lives in its own module because it is not
|
|
12
|
+
template-specific: it was written for template adoption (#3061) and the three
|
|
13
|
+
importer paths need the identical rule (#3069). One definition means a repaired row,
|
|
14
|
+
a seeded row and an imported row all agree about where "past the end" is.
|
|
15
|
+
|
|
16
|
+
Everything here is pure reads plus arithmetic — no writes, no locking. The caller
|
|
17
|
+
owns the transaction, and is responsible for holding it across the read and the
|
|
18
|
+
insert if concurrent writers are possible.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
from collections.abc import Iterable
|
|
24
|
+
from typing import Any
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def min_root_ordinal(paths: Iterable[str | None]) -> int | None:
|
|
28
|
+
"""The smallest numeric root label in ``paths``, or ``None`` if there is none.
|
|
29
|
+
|
|
30
|
+
Separated out because it is the half of the offset calculation that reads the
|
|
31
|
+
incoming document rather than the project, and because a caller that has already
|
|
32
|
+
computed it should not have to hand the whole path list over a second time.
|
|
33
|
+
"""
|
|
34
|
+
heads = (str(path).partition(".")[0] for path in paths if path)
|
|
35
|
+
return min((int(head) for head in heads if head.isdigit()), default=None)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def root_ordinal_offset(
|
|
39
|
+
project_id: Any,
|
|
40
|
+
*,
|
|
41
|
+
include_deleted: bool = False,
|
|
42
|
+
document_paths: Iterable[str | None] | None = None,
|
|
43
|
+
) -> int:
|
|
44
|
+
"""How far to shift an incoming document's root ordinals so they land past what exists.
|
|
45
|
+
|
|
46
|
+
Returns ``0`` for a project with no numeric root labels — so a first adoption is
|
|
47
|
+
shifted by nothing and keeps the document's paths exactly. Otherwise the shift
|
|
48
|
+
lands the document's *lowest* root ordinal one position past the project's
|
|
49
|
+
highest, which is what keeps the numbering contiguous across repeat adoptions.
|
|
50
|
+
|
|
51
|
+
``document_paths`` is the incoming document's paths. It defaults to ``None``,
|
|
52
|
+
which assumes the document numbers its roots from ``1`` — the convention this
|
|
53
|
+
module's docstring describes, and what every template and export we have does.
|
|
54
|
+
That assumption is the whole reason the parameter exists: a document carrying a
|
|
55
|
+
root of ``0`` (legal in ltree, and an ``.mpp`` or CSV can hold one) maps ``0``
|
|
56
|
+
onto the project's highest existing ordinal under a from-1 shift and collides
|
|
57
|
+
with it. Passing the real paths costs one pass over a list the caller already
|
|
58
|
+
has and removes the assumption. The default reproduces the previous behavior
|
|
59
|
+
exactly, so a caller that has not been updated is no worse off than before.
|
|
60
|
+
|
|
61
|
+
``include_deleted`` widens the scan to tombstoned rows. The uniqueness constraint
|
|
62
|
+
covers live rows only, so a tombstone cannot collide with anything being written
|
|
63
|
+
now — but it still *holds* its number, and a later restore has to have somewhere
|
|
64
|
+
to come back to. Callers allocating a number that a restore might later contend
|
|
65
|
+
with should pass ``True``; callers that only care about what is legal right now
|
|
66
|
+
can leave it ``False``.
|
|
67
|
+
"""
|
|
68
|
+
from django.db.models.expressions import RawSQL
|
|
69
|
+
|
|
70
|
+
from trueppm_api.apps.projects.models import Task
|
|
71
|
+
|
|
72
|
+
rows = Task.objects.filter(project_id=project_id, wbs_path__isnull=False)
|
|
73
|
+
if not include_deleted:
|
|
74
|
+
rows = rows.filter(is_deleted=False)
|
|
75
|
+
labels = (
|
|
76
|
+
# nosec B611 — static SQL literal (no user input), empty params list; the
|
|
77
|
+
# ltree subpath() call can't be expressed in the ORM. Bandit flags any RawSQL.
|
|
78
|
+
# nosemgrep: avoid-raw-sql
|
|
79
|
+
rows.annotate(root_label=RawSQL("subpath(projects_task.wbs_path, 0, 1)::text", [])) # nosec B611
|
|
80
|
+
.values_list("root_label", flat=True)
|
|
81
|
+
# Task.Meta.ordering is ["wbs_path", "name"], and Postgres requires every
|
|
82
|
+
# ORDER BY expression to appear in a SELECT DISTINCT list — so without this
|
|
83
|
+
# Django widens the DISTINCT key to (root_label, wbs_path, name), which is
|
|
84
|
+
# unique per task. The query then streams one row per task, plus a sort, to
|
|
85
|
+
# compute a single integer. Clearing the ordering is what makes the "distinct
|
|
86
|
+
# root labels" this docstring promises actually true.
|
|
87
|
+
.order_by()
|
|
88
|
+
.distinct()
|
|
89
|
+
)
|
|
90
|
+
highest = max((int(label) for label in labels if str(label).isdigit()), default=None)
|
|
91
|
+
if highest is None:
|
|
92
|
+
return 0
|
|
93
|
+
document_floor = 1 if document_paths is None else min_root_ordinal(document_paths)
|
|
94
|
+
if document_floor is None:
|
|
95
|
+
return 0
|
|
96
|
+
# Clamped at zero: a document numbered above the project's highest root already
|
|
97
|
+
# lands past it, and a negative shift would drag it back onto occupied ground.
|
|
98
|
+
return max(highest - document_floor + 1, 0)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def offset_wbs_path(path: str | None, offset: int) -> str | None:
|
|
102
|
+
"""Shift a path's leading segment by ``offset``, preserving its subtree.
|
|
103
|
+
|
|
104
|
+
Only the leading segment moves: every path in an incoming document is relative
|
|
105
|
+
to a fresh project rooted at ``1``, so remapping just the head keeps the
|
|
106
|
+
document's whole tree shape intact ("2.1.3" under offset 4 becomes "6.1.3").
|
|
107
|
+
That is also why the ancestor/descendant relationships the caller derives from
|
|
108
|
+
these paths — summary-task detection, for one — are unaffected by the shift.
|
|
109
|
+
|
|
110
|
+
A non-numeric root label is left alone: it cannot be offset meaningfully, and
|
|
111
|
+
the ``(project, wbs_path)`` constraint now rejects it loudly if it does collide.
|
|
112
|
+
"""
|
|
113
|
+
if not path or offset == 0:
|
|
114
|
+
return path or None
|
|
115
|
+
head, _, rest = str(path).partition(".")
|
|
116
|
+
if not head.isdigit():
|
|
117
|
+
return str(path)
|
|
118
|
+
shifted = str(int(head) + offset)
|
|
119
|
+
return f"{shifted}.{rest}" if rest else shifted
|
|
File without changes
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""Effective per-project resource capacity — the one place the override resolves.
|
|
2
|
+
|
|
3
|
+
``ProjectResource.units_override`` is a **per-project** capacity statement ("this
|
|
4
|
+
person is only half on this project"). Every per-project capacity read must resolve
|
|
5
|
+
it the same way, or two adjacent surfaces report different numbers for the same
|
|
6
|
+
person on the same day (#3574).
|
|
7
|
+
|
|
8
|
+
The fallback expression itself was duplicated across the model, the serializer and
|
|
9
|
+
the utilization engine (#1582). Every Python resolution now goes through
|
|
10
|
+
:func:`effective_units`. There is exactly ONE other copy, and it is unavoidable:
|
|
11
|
+
``annotate_tasks_queryset`` resolves the same rule SQL-side as
|
|
12
|
+
``Coalesce("units_override", "resource__max_units")`` because the comparison happens
|
|
13
|
+
inside a subquery's HAVING. Keep the two in step; do not add a third.
|
|
14
|
+
|
|
15
|
+
Cross-project reads (``resource-contention``, and any other span that aggregates
|
|
16
|
+
several projects at once) deliberately keep ``Resource.max_units``: a slice of one
|
|
17
|
+
person's time on one project is not a statement about their total capacity, and the
|
|
18
|
+
slices are not additive.
|
|
19
|
+
|
|
20
|
+
This module is the OSS-side read surface for that fact. A cross-project consumer that
|
|
21
|
+
aggregates per-project capacity must **call** :func:`projects_effective_units` rather
|
|
22
|
+
than re-derive the fallback — a second copy of it is how #3574 happened, and any
|
|
23
|
+
reimplementation reaching for ``units_override or max_units`` gets the legitimate ``0``
|
|
24
|
+
wrong.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
from decimal import Decimal
|
|
30
|
+
from typing import TYPE_CHECKING, Any
|
|
31
|
+
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
from collections.abc import Iterable
|
|
34
|
+
|
|
35
|
+
# Stand-in when a resource row carries no capacity at all. Mirrors
|
|
36
|
+
# ``Resource.max_units``' own model default (full time), rendered at the field's two
|
|
37
|
+
# decimal places so a fallback and a stored value serialize identically.
|
|
38
|
+
DEFAULT_MAX_UNITS = Decimal("1.00")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def effective_units(
|
|
42
|
+
units_override: Decimal | None,
|
|
43
|
+
max_units: Decimal | None,
|
|
44
|
+
) -> Decimal:
|
|
45
|
+
"""Resolve one resource's effective capacity on one project.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
units_override: ``ProjectResource.units_override`` for this (project,
|
|
49
|
+
resource) pair, or ``None`` when the pair has no roster row or the
|
|
50
|
+
roster row sets no override.
|
|
51
|
+
max_units: ``Resource.max_units``, the resource's default capacity.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
The override when one is set, otherwise the resource default.
|
|
55
|
+
|
|
56
|
+
``units_override`` is nullable **and** ``0`` is a legitimate stored value — a
|
|
57
|
+
person rostered on a project but holding no capacity there. The test is
|
|
58
|
+
therefore ``is not None`` and never truthiness: ``units_override or max_units``
|
|
59
|
+
would silently promote a deliberate 0 back to full time, which is the inverse of
|
|
60
|
+
what the override was set to say.
|
|
61
|
+
"""
|
|
62
|
+
if units_override is not None:
|
|
63
|
+
return Decimal(units_override)
|
|
64
|
+
if max_units is not None:
|
|
65
|
+
return Decimal(max_units)
|
|
66
|
+
return DEFAULT_MAX_UNITS
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def project_effective_units(project_id: Any) -> dict[str, Decimal]:
|
|
70
|
+
"""Map ``str(resource_id) -> effective capacity`` for one project's roster.
|
|
71
|
+
|
|
72
|
+
One query. Resources with assignments on the project but no roster row are
|
|
73
|
+
absent from the map by construction — callers fall back to
|
|
74
|
+
``Resource.max_units`` for those, which is what an unrostered assignee's
|
|
75
|
+
capacity is.
|
|
76
|
+
"""
|
|
77
|
+
return projects_effective_units([project_id]).get(str(project_id), {})
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def resource_effective_units(project_id: Any, resource: Any) -> Decimal:
|
|
81
|
+
"""One resource's effective capacity on one project — a single-row lookup.
|
|
82
|
+
|
|
83
|
+
For callers that need exactly one pair. Hits the
|
|
84
|
+
``uniq_project_resource_project_resource`` unique index rather than reading the
|
|
85
|
+
whole roster; use :func:`project_effective_units` when several are needed.
|
|
86
|
+
Falls back to ``resource.max_units`` when the resource is not on the roster.
|
|
87
|
+
"""
|
|
88
|
+
from trueppm_api.apps.resources.models import ProjectResource
|
|
89
|
+
|
|
90
|
+
row = (
|
|
91
|
+
ProjectResource.objects.filter(
|
|
92
|
+
project_id=project_id, resource_id=resource.pk, is_deleted=False
|
|
93
|
+
)
|
|
94
|
+
.values_list("units_override")
|
|
95
|
+
.first()
|
|
96
|
+
)
|
|
97
|
+
return effective_units(row[0] if row is not None else None, resource.max_units)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def projects_effective_units(project_ids: Iterable[Any]) -> dict[str, dict[str, Decimal]]:
|
|
101
|
+
"""Batched :func:`project_effective_units` — one query for many projects.
|
|
102
|
+
|
|
103
|
+
Returns ``{str(project_id): {str(resource_id): capacity}}``. Callers that span
|
|
104
|
+
several projects (the batched sprint capacity path, #1012) use this so threading
|
|
105
|
+
the override does not reintroduce a per-project query.
|
|
106
|
+
"""
|
|
107
|
+
from trueppm_api.apps.resources.models import ProjectResource
|
|
108
|
+
|
|
109
|
+
ids = [pid for pid in project_ids if pid is not None]
|
|
110
|
+
if not ids:
|
|
111
|
+
return {}
|
|
112
|
+
|
|
113
|
+
out: dict[str, dict[str, Decimal]] = {}
|
|
114
|
+
rows = ProjectResource.objects.filter(project_id__in=ids, is_deleted=False).values_list(
|
|
115
|
+
"project_id", "resource_id", "units_override", "resource__max_units"
|
|
116
|
+
)
|
|
117
|
+
for project_id, resource_id, units_override, max_units in rows:
|
|
118
|
+
out.setdefault(str(project_id), {})[str(resource_id)] = effective_units(
|
|
119
|
+
units_override, max_units
|
|
120
|
+
)
|
|
121
|
+
return out
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Initial migration for resources app."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import uuid
|
|
6
|
+
|
|
7
|
+
import django.db.models.deletion
|
|
8
|
+
from django.db import migrations, models
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Migration(migrations.Migration):
|
|
12
|
+
initial = True
|
|
13
|
+
|
|
14
|
+
dependencies = [
|
|
15
|
+
("projects", "0001_initial"),
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
operations = [
|
|
19
|
+
migrations.CreateModel(
|
|
20
|
+
name="Resource",
|
|
21
|
+
fields=[
|
|
22
|
+
("id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True)),
|
|
23
|
+
("server_version", models.BigIntegerField(default=0, editable=False)),
|
|
24
|
+
("name", models.CharField(max_length=255)),
|
|
25
|
+
("email", models.EmailField(blank=True)),
|
|
26
|
+
(
|
|
27
|
+
"calendar",
|
|
28
|
+
models.ForeignKey(
|
|
29
|
+
blank=True,
|
|
30
|
+
null=True,
|
|
31
|
+
on_delete=django.db.models.deletion.PROTECT,
|
|
32
|
+
related_name="resources",
|
|
33
|
+
to="projects.calendar",
|
|
34
|
+
),
|
|
35
|
+
),
|
|
36
|
+
("max_units", models.DecimalField(decimal_places=2, default=1.0, max_digits=4)),
|
|
37
|
+
],
|
|
38
|
+
options={"db_table": "resources_resource", "ordering": ["name"]},
|
|
39
|
+
),
|
|
40
|
+
migrations.CreateModel(
|
|
41
|
+
name="TaskResource",
|
|
42
|
+
fields=[
|
|
43
|
+
("id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True)),
|
|
44
|
+
(
|
|
45
|
+
"task",
|
|
46
|
+
models.ForeignKey(
|
|
47
|
+
on_delete=django.db.models.deletion.CASCADE,
|
|
48
|
+
related_name="assignments",
|
|
49
|
+
to="projects.task",
|
|
50
|
+
),
|
|
51
|
+
),
|
|
52
|
+
(
|
|
53
|
+
"resource",
|
|
54
|
+
models.ForeignKey(
|
|
55
|
+
on_delete=django.db.models.deletion.CASCADE,
|
|
56
|
+
related_name="assignments",
|
|
57
|
+
to="resources.resource",
|
|
58
|
+
),
|
|
59
|
+
),
|
|
60
|
+
("units", models.DecimalField(decimal_places=2, default=1.0, max_digits=4)),
|
|
61
|
+
],
|
|
62
|
+
options={"db_table": "resources_task_resource"},
|
|
63
|
+
),
|
|
64
|
+
migrations.AlterUniqueTogether(
|
|
65
|
+
name="taskresource",
|
|
66
|
+
unique_together={("task", "resource")},
|
|
67
|
+
),
|
|
68
|
+
]
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# Generated by Django 5.2.14 on 2026-06-23 21:38
|
|
2
|
+
|
|
3
|
+
import uuid
|
|
4
|
+
|
|
5
|
+
import django.db.models.deletion
|
|
6
|
+
from django.conf import settings
|
|
7
|
+
from django.db import migrations, models
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Migration(migrations.Migration):
|
|
11
|
+
replaces = [
|
|
12
|
+
("resources", "0001_initial"),
|
|
13
|
+
("resources", "0002_alter_uuid_pk_serialize_false"),
|
|
14
|
+
("resources", "0003_resource_soft_delete"),
|
|
15
|
+
("resources", "0004_add_taskresource_resource_index"),
|
|
16
|
+
("resources", "0005_resource_job_role"),
|
|
17
|
+
("resources", "0006_skill"),
|
|
18
|
+
("resources", "0007_resource_skill"),
|
|
19
|
+
("resources", "0008_project_resource"),
|
|
20
|
+
("resources", "0009_task_skill_requirement"),
|
|
21
|
+
("resources", "0010_alter_resourceskill_options_and_more"),
|
|
22
|
+
("resources", "0011_alter_projectresource_notes"),
|
|
23
|
+
("resources", "0012_add_resource_user_fk"),
|
|
24
|
+
("resources", "0013_alter_projectresource_unique_together_and_more"),
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
initial = True
|
|
28
|
+
|
|
29
|
+
dependencies = [
|
|
30
|
+
("projects", "0001_initial"),
|
|
31
|
+
("projects", "0018_estimation_governance"),
|
|
32
|
+
("projects", "0078_alter_risktask_unique_together_and_more"),
|
|
33
|
+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
operations = [
|
|
37
|
+
migrations.CreateModel(
|
|
38
|
+
name="Resource",
|
|
39
|
+
fields=[
|
|
40
|
+
(
|
|
41
|
+
"id",
|
|
42
|
+
models.UUIDField(
|
|
43
|
+
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
|
|
44
|
+
),
|
|
45
|
+
),
|
|
46
|
+
("server_version", models.BigIntegerField(default=0, editable=False)),
|
|
47
|
+
("name", models.CharField(max_length=255)),
|
|
48
|
+
("email", models.EmailField(blank=True, max_length=254)),
|
|
49
|
+
(
|
|
50
|
+
"calendar",
|
|
51
|
+
models.ForeignKey(
|
|
52
|
+
blank=True,
|
|
53
|
+
null=True,
|
|
54
|
+
on_delete=django.db.models.deletion.PROTECT,
|
|
55
|
+
related_name="resources",
|
|
56
|
+
to="projects.calendar",
|
|
57
|
+
),
|
|
58
|
+
),
|
|
59
|
+
("max_units", models.DecimalField(decimal_places=2, default=1.0, max_digits=4)),
|
|
60
|
+
("is_deleted", models.BooleanField(db_index=True, default=False)),
|
|
61
|
+
("deleted_version", models.BigIntegerField(blank=True, editable=False, null=True)),
|
|
62
|
+
("job_role", models.CharField(blank=True, max_length=120)),
|
|
63
|
+
(
|
|
64
|
+
"user",
|
|
65
|
+
models.ForeignKey(
|
|
66
|
+
blank=True,
|
|
67
|
+
null=True,
|
|
68
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
|
69
|
+
related_name="resources",
|
|
70
|
+
to=settings.AUTH_USER_MODEL,
|
|
71
|
+
),
|
|
72
|
+
),
|
|
73
|
+
],
|
|
74
|
+
options={
|
|
75
|
+
"db_table": "resources_resource",
|
|
76
|
+
"ordering": ["name"],
|
|
77
|
+
},
|
|
78
|
+
),
|
|
79
|
+
migrations.CreateModel(
|
|
80
|
+
name="Skill",
|
|
81
|
+
fields=[
|
|
82
|
+
(
|
|
83
|
+
"id",
|
|
84
|
+
models.UUIDField(
|
|
85
|
+
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
|
|
86
|
+
),
|
|
87
|
+
),
|
|
88
|
+
("server_version", models.BigIntegerField(default=0, editable=False)),
|
|
89
|
+
("is_deleted", models.BooleanField(db_index=True, default=False)),
|
|
90
|
+
("deleted_version", models.BigIntegerField(blank=True, editable=False, null=True)),
|
|
91
|
+
("name", models.CharField(max_length=120)),
|
|
92
|
+
("normalized_name", models.CharField(max_length=120, unique=True)),
|
|
93
|
+
("category", models.CharField(blank=True, max_length=60)),
|
|
94
|
+
],
|
|
95
|
+
options={
|
|
96
|
+
"db_table": "resources_skill",
|
|
97
|
+
"ordering": ["name"],
|
|
98
|
+
},
|
|
99
|
+
),
|
|
100
|
+
migrations.CreateModel(
|
|
101
|
+
name="ProjectResource",
|
|
102
|
+
fields=[
|
|
103
|
+
(
|
|
104
|
+
"id",
|
|
105
|
+
models.UUIDField(
|
|
106
|
+
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
|
|
107
|
+
),
|
|
108
|
+
),
|
|
109
|
+
("server_version", models.BigIntegerField(default=0, editable=False)),
|
|
110
|
+
("is_deleted", models.BooleanField(db_index=True, default=False)),
|
|
111
|
+
("deleted_version", models.BigIntegerField(blank=True, editable=False, null=True)),
|
|
112
|
+
(
|
|
113
|
+
"project",
|
|
114
|
+
models.ForeignKey(
|
|
115
|
+
on_delete=django.db.models.deletion.CASCADE,
|
|
116
|
+
related_name="resource_pool",
|
|
117
|
+
to="projects.project",
|
|
118
|
+
),
|
|
119
|
+
),
|
|
120
|
+
(
|
|
121
|
+
"resource",
|
|
122
|
+
models.ForeignKey(
|
|
123
|
+
on_delete=django.db.models.deletion.CASCADE,
|
|
124
|
+
related_name="project_memberships",
|
|
125
|
+
to="resources.resource",
|
|
126
|
+
),
|
|
127
|
+
),
|
|
128
|
+
("role_title", models.CharField(blank=True, max_length=120)),
|
|
129
|
+
(
|
|
130
|
+
"units_override",
|
|
131
|
+
models.DecimalField(blank=True, decimal_places=2, max_digits=4, null=True),
|
|
132
|
+
),
|
|
133
|
+
("notes", models.TextField(blank=True, default="")),
|
|
134
|
+
],
|
|
135
|
+
options={
|
|
136
|
+
"db_table": "resources_project_resource",
|
|
137
|
+
"unique_together": set(),
|
|
138
|
+
"indexes": [
|
|
139
|
+
models.Index(fields=["project", "is_deleted"], name="proj_res_proj_del_idx")
|
|
140
|
+
],
|
|
141
|
+
"constraints": [
|
|
142
|
+
models.UniqueConstraint(
|
|
143
|
+
fields=("project", "resource"),
|
|
144
|
+
name="uniq_project_resource_project_resource",
|
|
145
|
+
)
|
|
146
|
+
],
|
|
147
|
+
},
|
|
148
|
+
),
|
|
149
|
+
migrations.CreateModel(
|
|
150
|
+
name="ResourceSkill",
|
|
151
|
+
fields=[
|
|
152
|
+
(
|
|
153
|
+
"id",
|
|
154
|
+
models.UUIDField(
|
|
155
|
+
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
|
|
156
|
+
),
|
|
157
|
+
),
|
|
158
|
+
("server_version", models.BigIntegerField(default=0, editable=False)),
|
|
159
|
+
("is_deleted", models.BooleanField(db_index=True, default=False)),
|
|
160
|
+
("deleted_version", models.BigIntegerField(blank=True, editable=False, null=True)),
|
|
161
|
+
(
|
|
162
|
+
"resource",
|
|
163
|
+
models.ForeignKey(
|
|
164
|
+
on_delete=django.db.models.deletion.CASCADE,
|
|
165
|
+
related_name="skills",
|
|
166
|
+
to="resources.resource",
|
|
167
|
+
),
|
|
168
|
+
),
|
|
169
|
+
(
|
|
170
|
+
"skill",
|
|
171
|
+
models.ForeignKey(
|
|
172
|
+
on_delete=django.db.models.deletion.PROTECT,
|
|
173
|
+
related_name="resources",
|
|
174
|
+
to="resources.skill",
|
|
175
|
+
),
|
|
176
|
+
),
|
|
177
|
+
(
|
|
178
|
+
"proficiency",
|
|
179
|
+
models.IntegerField(
|
|
180
|
+
choices=[(1, "Beginner"), (2, "Intermediate"), (3, "Expert")], default=2
|
|
181
|
+
),
|
|
182
|
+
),
|
|
183
|
+
],
|
|
184
|
+
options={
|
|
185
|
+
"db_table": "resources_resource_skill",
|
|
186
|
+
"unique_together": set(),
|
|
187
|
+
"indexes": [
|
|
188
|
+
models.Index(fields=["skill", "proficiency"], name="res_skill_prof_idx")
|
|
189
|
+
],
|
|
190
|
+
"ordering": ["skill__name"],
|
|
191
|
+
"constraints": [
|
|
192
|
+
models.UniqueConstraint(
|
|
193
|
+
fields=("resource", "skill"), name="uniq_resource_skill_resource_skill"
|
|
194
|
+
)
|
|
195
|
+
],
|
|
196
|
+
},
|
|
197
|
+
),
|
|
198
|
+
migrations.CreateModel(
|
|
199
|
+
name="TaskResource",
|
|
200
|
+
fields=[
|
|
201
|
+
(
|
|
202
|
+
"id",
|
|
203
|
+
models.UUIDField(
|
|
204
|
+
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
|
|
205
|
+
),
|
|
206
|
+
),
|
|
207
|
+
(
|
|
208
|
+
"task",
|
|
209
|
+
models.ForeignKey(
|
|
210
|
+
on_delete=django.db.models.deletion.CASCADE,
|
|
211
|
+
related_name="assignments",
|
|
212
|
+
to="projects.task",
|
|
213
|
+
),
|
|
214
|
+
),
|
|
215
|
+
(
|
|
216
|
+
"resource",
|
|
217
|
+
models.ForeignKey(
|
|
218
|
+
on_delete=django.db.models.deletion.CASCADE,
|
|
219
|
+
related_name="assignments",
|
|
220
|
+
to="resources.resource",
|
|
221
|
+
),
|
|
222
|
+
),
|
|
223
|
+
("units", models.DecimalField(decimal_places=2, default=1.0, max_digits=4)),
|
|
224
|
+
],
|
|
225
|
+
options={
|
|
226
|
+
"db_table": "resources_task_resource",
|
|
227
|
+
"unique_together": set(),
|
|
228
|
+
"constraints": [
|
|
229
|
+
models.UniqueConstraint(
|
|
230
|
+
fields=("task", "resource"), name="uniq_task_resource_task_resource"
|
|
231
|
+
)
|
|
232
|
+
],
|
|
233
|
+
},
|
|
234
|
+
),
|
|
235
|
+
migrations.CreateModel(
|
|
236
|
+
name="TaskSkillRequirement",
|
|
237
|
+
fields=[
|
|
238
|
+
(
|
|
239
|
+
"id",
|
|
240
|
+
models.UUIDField(
|
|
241
|
+
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
|
|
242
|
+
),
|
|
243
|
+
),
|
|
244
|
+
("server_version", models.BigIntegerField(default=0, editable=False)),
|
|
245
|
+
("is_deleted", models.BooleanField(db_index=True, default=False)),
|
|
246
|
+
("deleted_version", models.BigIntegerField(blank=True, editable=False, null=True)),
|
|
247
|
+
(
|
|
248
|
+
"task",
|
|
249
|
+
models.ForeignKey(
|
|
250
|
+
on_delete=django.db.models.deletion.CASCADE,
|
|
251
|
+
related_name="skill_requirements",
|
|
252
|
+
to="projects.task",
|
|
253
|
+
),
|
|
254
|
+
),
|
|
255
|
+
(
|
|
256
|
+
"skill",
|
|
257
|
+
models.ForeignKey(
|
|
258
|
+
on_delete=django.db.models.deletion.PROTECT,
|
|
259
|
+
related_name="task_requirements",
|
|
260
|
+
to="resources.skill",
|
|
261
|
+
),
|
|
262
|
+
),
|
|
263
|
+
(
|
|
264
|
+
"min_proficiency",
|
|
265
|
+
models.IntegerField(
|
|
266
|
+
choices=[(1, "Beginner"), (2, "Intermediate"), (3, "Expert")], default=1
|
|
267
|
+
),
|
|
268
|
+
),
|
|
269
|
+
],
|
|
270
|
+
options={
|
|
271
|
+
"db_table": "resources_task_skill_requirement",
|
|
272
|
+
"unique_together": set(),
|
|
273
|
+
"ordering": ["skill__name"],
|
|
274
|
+
"constraints": [
|
|
275
|
+
models.UniqueConstraint(
|
|
276
|
+
fields=("task", "skill"), name="uniq_task_skill_req_task_skill"
|
|
277
|
+
)
|
|
278
|
+
],
|
|
279
|
+
},
|
|
280
|
+
),
|
|
281
|
+
]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Add serialize=False to UUID primary key fields.
|
|
2
|
+
|
|
3
|
+
Django 5's migration autodetector expects primary_key=True UUIDs to also
|
|
4
|
+
carry serialize=False in the migration state. Without it, makemigrations
|
|
5
|
+
--check reports spurious "Alter field id" operations on every run.
|
|
6
|
+
No database schema change is made by these operations.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import uuid
|
|
12
|
+
|
|
13
|
+
from django.db import migrations, models
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Migration(migrations.Migration):
|
|
17
|
+
dependencies = [
|
|
18
|
+
("resources", "0001_initial"),
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
operations = [
|
|
22
|
+
migrations.AlterField(
|
|
23
|
+
model_name="resource",
|
|
24
|
+
name="id",
|
|
25
|
+
field=models.UUIDField(
|
|
26
|
+
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
|
|
27
|
+
),
|
|
28
|
+
),
|
|
29
|
+
migrations.AlterField(
|
|
30
|
+
model_name="taskresource",
|
|
31
|
+
name="id",
|
|
32
|
+
field=models.UUIDField(
|
|
33
|
+
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
|
|
34
|
+
),
|
|
35
|
+
),
|
|
36
|
+
]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Add soft-delete fields to Resource.
|
|
2
|
+
|
|
3
|
+
VersionedModel gained is_deleted and deleted_version in the projects 0004
|
|
4
|
+
migration. Resource extends VersionedModel and needs the same columns so
|
|
5
|
+
the schema matches the model definition. TaskResource extends models.Model
|
|
6
|
+
directly and does not need these fields.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from django.db import migrations, models
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Migration(migrations.Migration):
|
|
15
|
+
dependencies = [
|
|
16
|
+
("resources", "0002_alter_uuid_pk_serialize_false"),
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
operations = [
|
|
20
|
+
migrations.AddField(
|
|
21
|
+
model_name="resource",
|
|
22
|
+
name="is_deleted",
|
|
23
|
+
field=models.BooleanField(db_index=True, default=False),
|
|
24
|
+
),
|
|
25
|
+
migrations.AddField(
|
|
26
|
+
model_name="resource",
|
|
27
|
+
name="deleted_version",
|
|
28
|
+
field=models.BigIntegerField(blank=True, editable=False, null=True),
|
|
29
|
+
),
|
|
30
|
+
]
|