aa-bb 3.2.4__tar.gz → 3.2.4b2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/PKG-INFO +1 -1
  2. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/__init__.py +1 -1
  3. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/admin.py +0 -3
  4. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/app_settings.py +15 -462
  5. aa_bb-3.2.4b2/aa_bb/apps.py +271 -0
  6. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks/add_to_blacklist.py +2 -6
  7. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks/awox.py +6 -10
  8. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks/clone_state.py +1 -0
  9. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks/hostile_assets.py +13 -18
  10. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks/hostile_clones.py +16 -24
  11. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks/sus_contacts.py +6 -9
  12. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks/sus_contracts.py +21 -80
  13. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks/sus_mails.py +39 -67
  14. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks/sus_trans.py +38 -94
  15. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks_cb/hostile_assets.py +9 -19
  16. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks_cb/sus_contracts.py +2 -47
  17. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks_cb/sus_trans.py +24 -61
  18. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/models.py +205 -226
  19. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/signals.py +4 -20
  20. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/tasks.py +220 -73
  21. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/tasks_bot.py +2 -29
  22. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/tasks_cb.py +324 -117
  23. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/tasks_ct.py +5 -18
  24. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/tasks_other.py +27 -56
  25. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/tasks_tickets.py +32 -84
  26. aa_bb-3.2.4b2/aa_bb/tasks_utils.py +115 -0
  27. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/loa/admin.html +17 -18
  28. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/views.py +27 -106
  29. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/views_cb.py +2 -11
  30. aa_bb-3.2.4/aa_bb/apps.py +0 -68
  31. aa_bb-3.2.4/aa_bb/migrations/0094_bigbrotherconfig_corp_compliance_webhook_and_more.py +0 -28
  32. aa_bb-3.2.4/aa_bb/migrations/0095_alter_bigbrotherconfig_limit_to_main_corp.py +0 -18
  33. aa_bb-3.2.4/aa_bb/migrations/0096_bigbrotherconfig_clone_state_notify_and_more.py +0 -23
  34. aa_bb-3.2.4/aa_bb/tasks_utils.py +0 -328
  35. aa_bb-3.2.4/aa_bb/tests/test_sus_trans.py +0 -226
  36. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/.gitignore +0 -0
  37. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/LICENSE +0 -0
  38. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/README.md +0 -0
  39. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/auth_hooks.py +0 -0
  40. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/celery.py +0 -0
  41. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks/__init__.py +0 -0
  42. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks/alliance_blacklist.py +0 -0
  43. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks/alpha_skills.json +0 -0
  44. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks/coalition_blacklist.py +0 -0
  45. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks/corp_changes.py +0 -0
  46. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks/cyno.py +0 -0
  47. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks/roles_and_tokens.py +0 -0
  48. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks/skills.json +0 -0
  49. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks/skills.py +0 -0
  50. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/checks_cb/__init__.py +0 -0
  51. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/esi_cache.py +0 -0
  52. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/esi_client.py +0 -0
  53. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/forms.py +0 -0
  54. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/locale/.gitkeep +0 -0
  55. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/management/__init__.py +0 -0
  56. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/management/commands/__init__.py +0 -0
  57. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0001_initial.py +0 -0
  58. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0002_bigbrotherconfig_userstatus.py +0 -0
  59. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0003_alter_bigbrotherconfig_pingroleid.py +0 -0
  60. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0004_alter_bigbrotherconfig_is_active_and_more.py +0 -0
  61. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0005_alter_bigbrotherconfig_hostile_alliances.py +0 -0
  62. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0006_alter_bigbrotherconfig_pingroleid.py +0 -0
  63. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0007_alter_general_options.py +0 -0
  64. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0008_alliance_names_corporation_names.py +0 -0
  65. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0009_userstatus_sus_contacts_userstatus_sus_contracts_and_more.py +0 -0
  66. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0010_alter_userstatus_awox_kill_links_and_more.py +0 -0
  67. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0011_character_names.py +0 -0
  68. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0012_id_types.py +0 -0
  69. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0013_bigbrotherconfig_mail_keywords.py +0 -0
  70. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0014_processedcontract_processedmail_and_more.py +0 -0
  71. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0015_processedtransaction_sustransactionnote.py +0 -0
  72. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0016_warmprogress.py +0 -0
  73. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0017_entityinfocache.py +0 -0
  74. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0018_userstatus_cyno_userstatus_has_skills_and_more.py +0 -0
  75. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0019_bigbrotherconfig_whitelist_alliances_and_more.py +0 -0
  76. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0020_messages_bigbrotherconfig_are_daily_messages_active_and_more.py +0 -0
  77. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0021_alter_messages_id_alter_messages_text.py +0 -0
  78. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0022_messages_sent_in_cycle.py +0 -0
  79. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0023_optmessages1_optmessages2_optmessages3_optmessages4_and_more.py +0 -0
  80. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0024_bigbrotherconfig_dailyschedule_and_more.py +0 -0
  81. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0025_alter_messages_options_alter_optmessages1_options_and_more.py +0 -0
  82. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0026_alter_general_options_alter_bigbrotherconfig_id_and_more.py +0 -0
  83. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0027_alter_general_options_bigbrotherconfig_is_loa_active_and_more.py +0 -0
  84. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0028_alter_bigbrotherconfig_is_loa_active.py +0 -0
  85. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0029_leaverequest_main_character.py +0 -0
  86. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0030_alter_general_options.py +0 -0
  87. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0031_bigbrotherconfig_loa_max_logoff_days_and_more.py +0 -0
  88. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0032_alter_leaverequest_status.py +0 -0
  89. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0033_messagetype_bigbrotherconfig_pingroleid2_and_more.py +0 -0
  90. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0034_rename_last_updated_userstatus_updated.py +0 -0
  91. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0035_alter_userstatus_options.py +0 -0
  92. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0036_alter_general_options.py +0 -0
  93. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0037_corpstatus.py +0 -0
  94. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0038_bigbrotherconfig_ignored_corporations.py +0 -0
  95. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0039_alter_bigbrotherconfig_ignored_corporations.py +0 -0
  96. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0040_sovereigntymapcache_corporationinfocache_and_more.py +0 -0
  97. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0041_bigbrotherconfig_is_warmer_active.py +0 -0
  98. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0042_alter_general_options_and_more.py +0 -0
  99. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0043_bigbrotherconfig_bb_member_states_and_more.py +0 -0
  100. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0044_bigbrotherconfig_character_scopes_and_more.py +0 -0
  101. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0045_userstatus_sp_age_ratio_result.py +0 -0
  102. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0046_bigbrotherconfig_member_corporations.py +0 -0
  103. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0047_bigbrotherconfig_member_alliances.py +0 -0
  104. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0048_characteraccountstate.py +0 -0
  105. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0049_userstatus_clone_status.py +0 -0
  106. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0050_alter_general_options_and_more.py +0 -0
  107. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0051_monthlypapstats.py +0 -0
  108. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0052_papsconfig_delete_monthlypapstats.py +0 -0
  109. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0053_alter_papsconfig_corp_modifier_and_more.py +0 -0
  110. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0054_alter_general_options.py +0 -0
  111. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0055_papsconfig_group_paps_papsconfig_group_paps_modifier.py +0 -0
  112. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0056_alter_papsconfig_group_paps.py +0 -0
  113. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0057_papsconfig_excluded_groups_papsconfig_excluded_users_and_more.py +0 -0
  114. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0058_papsconfig_excluded_groups_get_paps_and_more.py +0 -0
  115. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0059_alter_papsconfig_excluded_groups_get_paps.py +0 -0
  116. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0060_papsconfig_cap_group_papsconfig_cap_group_paps_and_more.py +0 -0
  117. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0061_remove_papsconfig_cap_group_and_more.py +0 -0
  118. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0062_complianceticket.py +0 -0
  119. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0063_alter_complianceticket_user.py +0 -0
  120. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0064_alter_complianceticket_reason.py +0 -0
  121. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0065_alter_complianceticket_reason_and_more.py +0 -0
  122. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0066_tickettoolconfig_papcompliance.py +0 -0
  123. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0067_remove_tickettoolconfig_category_id_and_more.py +0 -0
  124. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0068_tickettoolconfig_category_id_and_more.py +0 -0
  125. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0069_tickettoolconfig_ticket_counter.py +0 -0
  126. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0070_remove_tickettoolconfig_role_id_and_more.py +0 -0
  127. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0071_tickettoolconfig_role_id.py +0 -0
  128. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0072_alter_complianceticket_reason.py +0 -0
  129. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0073_tickettoolconfig_starting_pap_compliance.py +0 -0
  130. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0074_alter_bigbrotherconfig_hostile_alliances.py +0 -0
  131. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0075_bbupdatestate_tickettoolconfig_afk_check_frequency_and_more.py +0 -0
  132. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0076_id_types_last_accessed_frequentcorpchangescache_and_more.py +0 -0
  133. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0077_complianceticket_ticket_id_and_more.py +0 -0
  134. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0078_tickettoolconfig_awox_monitor_enabled.py +0 -0
  135. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0079_helptext_guidance.py +0 -0
  136. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0080_bigbrotherconfig_dlc_flags.py +0 -0
  137. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0081_remove_papsconfig_imp_modifier_and_more.py +0 -0
  138. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0082_remove_bigbrotherconfig_token_and_more.py +0 -0
  139. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0083_alter_bigbrotherredditmessage_options_and_more.py +0 -0
  140. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0084_bigbrotherconfig_consider_all_structures_hostile_and_more.py +0 -0
  141. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0085_bigbrotherconfig_awox_notify_and_more.py +0 -0
  142. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0086_bigbrotherconfig_are_recurring_stats_active_and_more.py +0 -0
  143. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0087_bigbrotherconfig_dlc_are_recurring_stats_active.py +0 -0
  144. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0088_bigbrotherconfig_cyno_notify.py +0 -0
  145. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0089_bigbrotherconfig_asset_notify_and_more.py +0 -0
  146. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0090_alter_papsconfig_options_and_more.py +0 -0
  147. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0091_remove_bigbrotherconfig_dlc_are_recurring_stats_active_and_more.py +0 -0
  148. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0092_userstatus_baseline_initialized.py +0 -0
  149. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/0093_eveitemprice_delete_bigbrotherredditmessage_and_more.py +0 -0
  150. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/migrations/__init__.py +0 -0
  151. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/static/aa_bb/.gitkeep +0 -0
  152. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/static/aa_bb/js/admin_market_toggle.js +0 -0
  153. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/aa_bb/base.html +0 -0
  154. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/aa_bb/disabled.html +0 -0
  155. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/aa_bb/index.html +0 -0
  156. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/aa_cb/base.html +0 -0
  157. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/aa_cb/disabled.html +0 -0
  158. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/aa_cb/index.html +0 -0
  159. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/faq/base.html +0 -0
  160. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/faq/cards.html +0 -0
  161. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/faq/faq.html +0 -0
  162. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/faq/menu.html +0 -0
  163. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/faq/modules.html +0 -0
  164. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/faq/settings_bigbrother.html +0 -0
  165. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/faq/settings_nav.html +0 -0
  166. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/faq/settings_paps.html +0 -0
  167. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/faq/settings_stats.html +0 -0
  168. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/faq/settings_tickets.html +0 -0
  169. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/loa/_loa_subtabs.html +0 -0
  170. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/loa/base.html +0 -0
  171. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/loa/disabled.html +0 -0
  172. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/loa/index.html +0 -0
  173. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/loa/menu.html +0 -0
  174. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/loa/request.html +0 -0
  175. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/paps/base.html +0 -0
  176. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/paps/disabled.html +0 -0
  177. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/paps/history.html +0 -0
  178. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/paps/index.html +0 -0
  179. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/templates/paps/menu.html +0 -0
  180. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/tests/__init__.py +0 -0
  181. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/tests/test_clone_state_logic.py +0 -0
  182. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/tests/test_performance.py +0 -0
  183. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/tests/test_price_timer.py +0 -0
  184. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/tests/test_task_setup.py +0 -0
  185. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/tests/test_tasks_notifications.py +0 -0
  186. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/tests/test_views.py +0 -0
  187. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/urls.py +0 -0
  188. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/urls_cb.py +0 -0
  189. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/urls_loa.py +0 -0
  190. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/urls_paps.py +0 -0
  191. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/views_faq.py +0 -0
  192. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/aa_bb/views_paps.py +0 -0
  193. {aa_bb-3.2.4 → aa_bb-3.2.4b2}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aa_bb
3
- Version: 3.2.4
3
+ Version: 3.2.4b2
4
4
  Summary: BigBrother
5
5
  Project-URL: Changelog, https://github.com/BroodLK/aa_bb/blob/main/CHANGELOG.md
6
6
  Project-URL: Issue / Bug Reports, https://github.com/BroodLK/aa_bb/issues
@@ -1,4 +1,4 @@
1
1
  """Initialize the app"""
2
2
 
3
- __version__ = "3.2.4"
3
+ __version__ = "3.2.4b2"
4
4
  __title__ = "BigBrother"
@@ -63,7 +63,6 @@ class BB_ConfigAdmin(SingletonModelAdmin):
63
63
  "cyno_notify",
64
64
  "sp_inject_notify",
65
65
  "clone_notify",
66
- "clone_state_notify",
67
66
  "asset_notify",
68
67
  "contact_notify",
69
68
  "contract_notify",
@@ -140,8 +139,6 @@ class BB_ConfigAdmin(SingletonModelAdmin):
140
139
  "optwebhook3",
141
140
  "optwebhook4",
142
141
  "optwebhook5",
143
- "user_compliance_webhook",
144
- "corp_compliance_webhook",
145
142
  "stats_webhook",
146
143
  )
147
144
  },
@@ -19,7 +19,6 @@ from django.apps import apps
19
19
  from django.utils import timezone
20
20
  from typing import Optional, Dict, Tuple, Any, List
21
21
  from django.db import transaction, IntegrityError, OperationalError
22
- from django.db.models import Q
23
22
 
24
23
  from .models import (
25
24
  Alliance_names, Corporation_names, Character_names, BigBrotherConfig, id_types,
@@ -933,120 +932,33 @@ def resolve_character_name(char_id: int) -> str:
933
932
  return f"Unresolvable eve map{e_short}{e_detail}"
934
933
 
935
934
 
936
- def get_system_owner(system: Dict) -> Dict[str, str]:
935
+ def get_system_owner(system: str) -> Dict[str, str]:
937
936
  """
938
937
  Get sovereignty owner of an EVE system by name.
939
- Always returns a dict with keys: owner_id, owner_name, owner_type, region_id, region_name.
938
+ Always returns a dict with keys: owner_id, owner_name, owner_type.
940
939
  """
941
940
  owner_id = "0"
942
- owner_name = "Unresolvable Init"
941
+ owner_name = f"Unresolvable Init"
943
942
  owner_type = "unknown"
944
- region_id = "0"
945
- region_name = "Unknown Region"
946
943
 
947
944
  # 1) Pull name and ID from the passed-in dict
948
- system_id_raw = system.get("id")
949
- try:
950
- system_id = int(system_id_raw) if system_id_raw is not None else None
951
- except (ValueError, TypeError):
952
- system_id = None
953
-
945
+ system_id = system.get("id")
954
946
  system_nam = system.get("name")
955
947
  system_name = str()
956
948
  if system_nam: # Convert the provided name into a proper string when available.
957
949
  system_name = str(system_nam)
958
950
 
959
951
  try:
960
- # Resolve parent system if this is a location
961
- parent_system_id = resolve_location_system_id(system_id)
962
- if parent_system_id:
963
- try:
964
- from eveuniverse.models import EveSolarSystem
965
- sys_obj = EveSolarSystem.objects.select_related("eve_constellation__eve_region").get(id=parent_system_id)
966
- region_id = str(sys_obj.eve_constellation.eve_region.id)
967
- region_name = sys_obj.eve_constellation.eve_region.name
968
- except Exception:
969
- pass
970
-
971
952
  sov_map = _get_sov_map()
972
- # If it's a structure or station, we want the system it's in for SOV
973
- target_sov_id = parent_system_id or system_id
974
- entry = next((s for s in sov_map if s.get("system_id") == target_sov_id), None)
953
+ entry = next((s for s in sov_map if s.get("system_id") == system_id), None)
975
954
  if not entry:
976
- # Fallback for systems not in the sovereignty map (e.g. Highsec/Lowsec)
977
- # or for NPC stations.
978
- if target_sov_id:
979
- if 30000000 <= target_sov_id <= 34000000:
980
- try:
981
- from eveuniverse.models import EveSolarSystem
982
- sys_obj = EveSolarSystem.objects.get(id=target_sov_id)
983
- return {
984
- "owner_id": "0",
985
- "owner_name": "Unclaimed",
986
- "owner_type": "unknown",
987
- "region_id": region_id,
988
- "region_name": region_name
989
- }
990
- except Exception:
991
- pass
992
- elif 60000000 <= target_sov_id <= 64000000:
993
- try:
994
- from eveuniverse.models import EveStation
995
- station_obj = EveStation.objects.get(id=target_sov_id)
996
- if station_obj.owner_id:
997
- return {
998
- "owner_id": str(station_obj.owner_id),
999
- "owner_name": resolve_corporation_name(station_obj.owner_id),
1000
- "owner_type": "corporation",
1001
- "region_id": region_id,
1002
- "region_name": region_name
1003
- }
1004
- except Exception:
1005
- pass
1006
-
1007
- # If it's specifically a player structure ID that we can't resolve owner for
1008
- if system_id and is_player_structure(system_id):
1009
- try:
1010
- from corptools.models import Structure
1011
- struct = Structure.objects.filter(structure_id=system_id).select_related("corporation__corporation").first()
1012
- if struct and struct.corporation and struct.corporation.corporation:
1013
- return {
1014
- "owner_id": str(struct.corporation.corporation.corporation_id),
1015
- "owner_name": struct.corporation.corporation.corporation_name,
1016
- "owner_type": "corporation",
1017
- "region_id": region_id,
1018
- "region_name": region_name
1019
- }
1020
- except Exception:
1021
- pass
1022
-
1023
- return {
1024
- "owner_id": owner_id,
1025
- "owner_name": "Unresolvable structure due to lack of docking rights",
1026
- "owner_type": owner_type,
1027
- "region_id": region_id,
1028
- "region_name": region_name
1029
- }
1030
-
1031
- return {
1032
- "owner_id": owner_id,
1033
- "owner_name": "Unresolvable location",
1034
- "owner_type": owner_type,
1035
- "region_id": region_id,
1036
- "region_name": region_name
1037
- }
955
+ return {"owner_id": owner_id, "owner_name": f"Unresolvable structure due to lack of docking rights", "owner_type": owner_type}
1038
956
 
1039
957
  except Exception as e:
1040
958
  logger.exception(f"Failed to fetch sovereignty for system ID {system_id}: {e}")
1041
959
  e_short = e.__class__.__name__
1042
960
  e_detail = getattr(e, 'code', None) or getattr(e, 'status', None) or str(e)
1043
- return {
1044
- "owner_id": owner_id,
1045
- "owner_name": f"Unresolvable sov, {e_short}{e_detail}",
1046
- "owner_type": owner_type,
1047
- "region_id": region_id,
1048
- "region_name": region_name
1049
- }
961
+ return {"owner_id": owner_id, "owner_name": f"Unresolvable sov, {e_short}{e_detail}", "owner_type": owner_type}
1050
962
 
1051
963
  # 3) Determine owner ID and type
1052
964
  alliance_id = entry.get("alliance_id")
@@ -1058,13 +970,7 @@ def get_system_owner(system: Dict) -> Dict[str, str]:
1058
970
  owner_id = str(faction_id)
1059
971
  owner_type = "faction"
1060
972
  else:
1061
- return {
1062
- "owner_id": "0",
1063
- "owner_name": "Unclaimed",
1064
- "owner_type": "unknown",
1065
- "region_id": region_id,
1066
- "region_name": region_name
1067
- }
973
+ return {"owner_id": "0", "owner_name": "Unclaimed", "owner_type": "unknown"}
1068
974
 
1069
975
  # 4) Resolve owner name
1070
976
  try:
@@ -1073,88 +979,7 @@ def get_system_owner(system: Dict) -> Dict[str, str]:
1073
979
  owner_name = "Unresolvable owner"
1074
980
  owner_id = "0"
1075
981
  owner_type = "unknown"
1076
-
1077
- return {
1078
- "owner_id": owner_id,
1079
- "owner_name": owner_name,
1080
- "owner_type": owner_type,
1081
- "region_id": region_id,
1082
- "region_name": region_name
1083
- }
1084
-
1085
-
1086
- def is_location_hostile(location_id: int, system_id: int = None) -> bool:
1087
- """
1088
- Determines if a given location (structure, station, or system) is considered hostile.
1089
- Returns True if hostile, False if safe.
1090
- """
1091
- if not location_id and not system_id:
1092
- return False
1093
-
1094
- cfg = BigBrotherConfig.get_solo()
1095
- safe_entities = get_safe_entities()
1096
- hostile_alli_ids = {int(s) for s in (cfg.hostile_alliances or "").split(",") if s.strip().isdigit()}
1097
- hostile_corp_ids = {int(s) for s in (cfg.hostile_corporations or "").split(",") if s.strip().isdigit()}
1098
-
1099
- # Resolve location owner
1100
- owner_info = get_system_owner({"id": location_id or system_id})
1101
- oid = None
1102
- oname = ""
1103
- if owner_info:
1104
- try:
1105
- oid = int(owner_info.get("owner_id", 0))
1106
- except (ValueError, TypeError):
1107
- oid = None
1108
- oname = owner_info.get("owner_name", "")
1109
-
1110
- # If it's a structure
1111
- if location_id and is_player_structure(location_id):
1112
- # Friendly structure overrides system hostility
1113
- if oid and oid in safe_entities:
1114
- return False
1115
- # Hostile structure
1116
- if oid and (oid in hostile_alli_ids or oid in hostile_corp_ids):
1117
- return True
1118
- if "Unresolvable" in oname:
1119
- return True
1120
-
1121
- # Check system-level hostility
1122
- target_system = system_id or (resolve_location_system_id(location_id) if location_id else None)
1123
- if target_system:
1124
- # If the location we checked was a structure, oid is structure owner.
1125
- # We might also need to check system (sov) owner for nullsec flags.
1126
- if target_system != location_id:
1127
- sys_owner_info = get_system_owner({"id": target_system})
1128
- try:
1129
- soid = int(sys_owner_info.get("owner_id", 0))
1130
- except (ValueError, TypeError):
1131
- soid = None
1132
- else:
1133
- soid = oid
1134
-
1135
- # Base hostility from system owner
1136
- if soid:
1137
- if soid in hostile_alli_ids or soid in hostile_corp_ids:
1138
- return True
1139
-
1140
- # Consider nullsec hostile
1141
- if cfg.consider_nullsec_hostile and is_nullsec(target_system):
1142
- # Safe if system is owned by us/allies
1143
- if soid is not None and soid in safe_entities:
1144
- return False
1145
- # Otherwise, if we are in a friendly structure (handled above), it's safe.
1146
- # If we are here, it's either an NPC station or a hostile/unknown structure.
1147
- return True
1148
-
1149
- # General fallback for hostile lists if not already caught
1150
- if oid:
1151
- if oid in hostile_alli_ids or oid in hostile_corp_ids:
1152
- return True
1153
-
1154
- if "Unresolvable" in oname:
1155
- return True
1156
-
1157
- return False
982
+ return {"owner_id": owner_id, "owner_name": owner_name, "owner_type": owner_type}
1158
983
 
1159
984
 
1160
985
 
@@ -1166,10 +991,8 @@ def get_users():
1166
991
  member_states = cfg.bb_member_states.all()
1167
992
  qs = UserProfile.objects.filter(state__in=member_states).exclude(main_character=None)
1168
993
 
1169
- member_corps = {int(x) for x in (cfg.member_corporations or "").split(",") if x.strip().isdigit()}
1170
- member_allis = {int(x) for x in (cfg.member_alliances or "").split(",") if x.strip().isdigit()}
1171
- if member_corps or member_allis:
1172
- qs = qs.filter(Q(main_character__corporation_id__in=member_corps) | Q(main_character__alliance_id__in=member_allis))
994
+ if cfg.limit_to_main_corp and cfg.main_corporation_id:
995
+ qs = qs.filter(main_character__corporation_id=cfg.main_corporation_id)
1173
996
 
1174
997
  users = list(
1175
998
  qs.values_list("main_character__character_name", flat=True)
@@ -1183,10 +1006,8 @@ def get_user_profiles():
1183
1006
  member_states = cfg.bb_member_states.all()
1184
1007
  qs = UserProfile.objects.filter(state__in=member_states).exclude(main_character=None)
1185
1008
 
1186
- member_corps = {int(x) for x in (cfg.member_corporations or "").split(",") if x.strip().isdigit()}
1187
- member_allis = {int(x) for x in (cfg.member_alliances or "").split(",") if x.strip().isdigit()}
1188
- if member_corps or member_allis:
1189
- qs = qs.filter(Q(main_character__corporation_id__in=member_corps) | Q(main_character__alliance_id__in=member_allis))
1009
+ if cfg.limit_to_main_corp and cfg.main_corporation_id:
1010
+ qs = qs.filter(main_character__corporation_id=cfg.main_corporation_id)
1190
1011
 
1191
1012
  users = (
1192
1013
  qs.select_related("main_character", "user") # optimization
@@ -1204,10 +1025,9 @@ def get_user_id(character_name):
1204
1025
 
1205
1026
  def is_nullsec(system_id):
1206
1027
  try:
1207
- system_id = int(system_id)
1208
1028
  sys = EveSolarSystem.objects.get(id=system_id)
1209
1029
  return sys.security_status <= 0.0
1210
- except (EveSolarSystem.DoesNotExist, ValueError, TypeError):
1030
+ except EveSolarSystem.DoesNotExist:
1211
1031
  return False
1212
1032
 
1213
1033
  def is_player_structure(location_id):
@@ -1216,104 +1036,7 @@ def is_player_structure(location_id):
1216
1036
  (Citadel, Engineering Complex, Refinery) rather than an NPC station.
1217
1037
  Structure IDs are typically large (>= 1,000,000,000,000).
1218
1038
  """
1219
- try:
1220
- return int(location_id) >= 1_000_000_000_000
1221
- except (ValueError, TypeError):
1222
- return False
1223
-
1224
- def resolve_location_name(location_id: int) -> Optional[str]:
1225
- """
1226
- Attempts to resolve a location_id to a human-readable name.
1227
- 1) Solar System (30M-34M)
1228
- 2) NPC Station (60M-64M)
1229
- 3) Player Structure (>= 1T)
1230
- """
1231
- if not location_id:
1232
- return None
1233
-
1234
- try:
1235
- location_id = int(location_id)
1236
- except (ValueError, TypeError):
1237
- return None
1238
-
1239
- # 1) Solar System
1240
- if 30000000 <= location_id <= 34000000:
1241
- try:
1242
- from eveuniverse.models import EveSolarSystem
1243
- return EveSolarSystem.objects.get(id=location_id).name
1244
- except Exception:
1245
- pass
1246
-
1247
- # 2) NPC Station
1248
- if 60000000 <= location_id <= 64000000:
1249
- try:
1250
- from eveuniverse.models import EveStation
1251
- return EveStation.objects.get(id=location_id).name
1252
- except Exception:
1253
- pass
1254
-
1255
- # 3) Player Structure
1256
- if is_player_structure(location_id):
1257
- try:
1258
- from corptools.models import Structure
1259
- struct = Structure.objects.filter(structure_id=location_id).first()
1260
- if struct:
1261
- return struct.name
1262
- except Exception:
1263
- pass
1264
-
1265
- # Fallback to EveLocation
1266
- try:
1267
- from corptools.models import EveLocation
1268
- loc = EveLocation.objects.filter(location_id=location_id).first()
1269
- if loc:
1270
- return loc.location_name
1271
- except Exception:
1272
- pass
1273
-
1274
- return None
1275
-
1276
- def resolve_location_system_id(location_id: int) -> Optional[int]:
1277
- """
1278
- Attempts to resolve a location_id to its parent solar system ID.
1279
- """
1280
- if not location_id:
1281
- return None
1282
-
1283
- try:
1284
- location_id = int(location_id)
1285
- except (ValueError, TypeError):
1286
- return None
1287
-
1288
- # 1) Solar System
1289
- if 30000000 <= location_id <= 34000000:
1290
- return location_id
1291
-
1292
- # 2) NPC Station
1293
- if 60000000 <= location_id <= 64000000:
1294
- try:
1295
- from eveuniverse.models import EveStation
1296
- station = EveStation.objects.get(id=location_id)
1297
- return station.eve_solar_system_id
1298
- except Exception:
1299
- pass
1300
-
1301
- # 3) Player Structure
1302
- if is_player_structure(location_id):
1303
- try:
1304
- from corptools.models import Structure, EveLocation
1305
- struct = Structure.objects.filter(structure_id=location_id).first()
1306
- if struct:
1307
- return struct.system_id
1308
-
1309
- # Fallback to EveLocation for non-owned structures
1310
- loc = EveLocation.objects.filter(location_id=location_id).first()
1311
- if loc and loc.system_id:
1312
- return loc.system_id
1313
- except Exception:
1314
- pass
1315
-
1316
- return None
1039
+ return location_id >= 1_000_000_000_000
1317
1040
 
1318
1041
  def is_ship(type_id):
1319
1042
  """Checks if a type_id belongs to a ship."""
@@ -1641,173 +1364,3 @@ def send_message(message, hook: str = None):
1641
1364
  len(buffer),
1642
1365
  )
1643
1366
  _post_with_retries({"content": buffer})
1644
-
1645
-
1646
- def send_status_embed(
1647
- subject: str,
1648
- lines: List[str],
1649
- *,
1650
- override_title: Optional[str] = None,
1651
- color: int = 0xED4245, # Discord red
1652
- hook: Optional[str] = None,
1653
- ) -> None:
1654
- """
1655
- Send a Discord embed via the existing send_message() webhook.
1656
-
1657
- - subject: usually the corp name
1658
- - lines: list of lines to go into embed description
1659
- - override_title: optional explicit title
1660
- - color: embed accent color (int)
1661
- - hook: optional webhook URL override
1662
- """
1663
-
1664
- if VERBOSE_WEBHOOK_LOGGING:
1665
- logger.debug(
1666
- "✅ [AA-BB] - [Embed] - send_status_embed called | subject=%r | lines=%d",
1667
- subject,
1668
- len(lines) if lines else 0,
1669
- )
1670
-
1671
- # Defensive: never send empty embeds
1672
- if not lines:
1673
- if VERBOSE_WEBHOOK_LOGGING:
1674
- logger.debug("ℹ️ [AA-BB] - [Embed] - aborted: no lines supplied")
1675
- return
1676
-
1677
- # Discord limits
1678
- MAX_DESC = 4096
1679
- MAX_LINES = 50
1680
-
1681
- title = override_title if override_title is not None else subject
1682
-
1683
- if VERBOSE_WEBHOOK_LOGGING:
1684
- logger.debug(
1685
- "✅ [AA-BB] - [Embed] - title resolved | title=%r | color=%#x",
1686
- title,
1687
- color,
1688
- )
1689
-
1690
- # Trim excessive lines but keep tables / sections intact
1691
- safe_lines = lines[:MAX_LINES]
1692
- if len(lines) > MAX_LINES:
1693
- logger.warning(
1694
- "ℹ️ [AA-BB] - [Embed] - line cap exceeded | original=%d | capped=%d",
1695
- len(lines),
1696
- MAX_LINES,
1697
- )
1698
-
1699
- description = "\n".join(safe_lines)
1700
-
1701
- # Hard truncate if someone messed up
1702
- if len(description) > MAX_DESC:
1703
- logger.error(
1704
- "ℹ️ [AA-BB] - [Embed] - description overflow | chars=%d | truncating",
1705
- len(description),
1706
- )
1707
- description = description[: MAX_DESC - 3] + "..."
1708
-
1709
- if VERBOSE_WEBHOOK_LOGGING:
1710
- logger.debug(
1711
- "✅ [AA-BB] - [Embed] - payload ready | lines=%d | chars=%d",
1712
- len(safe_lines),
1713
- len(description),
1714
- )
1715
-
1716
- embed = {
1717
- "embeds": [
1718
- {
1719
- "title": title,
1720
- "description": description,
1721
- "color": color,
1722
- }
1723
- ]
1724
- }
1725
-
1726
- if VERBOSE_WEBHOOK_LOGGING:
1727
- logger.debug("✅ [AA-BB] - [Embed] - sending embed payload")
1728
-
1729
- time.sleep(0.25)
1730
- send_message(embed, hook=hook)
1731
-
1732
-
1733
- def _chunk_embed_lines(lines, max_chars=1900):
1734
- """
1735
- Split a list of lines into chunks whose joined text length
1736
- is <= max_chars, without breaking ``` code blocks.
1737
-
1738
- Returns: List[List[str]] – each inner list is one embed body.
1739
- """
1740
- # First, group into "segments": either a full code block or a run of normal lines
1741
- segments = []
1742
- current_segment = []
1743
- in_code = False
1744
-
1745
- for line in lines:
1746
- stripped = line.strip()
1747
-
1748
- if stripped.startswith("```"):
1749
- # Starting a new code block
1750
- if not in_code:
1751
- # flush any accumulated non-code segment
1752
- if current_segment:
1753
- segments.append(current_segment)
1754
- current_segment = []
1755
- in_code = True
1756
- current_segment = [line]
1757
- else:
1758
- # closing an existing code block
1759
- current_segment.append(line)
1760
- segments.append(current_segment)
1761
- current_segment = []
1762
- in_code = False
1763
- elif not in_code and (line.startswith("#") or line.startswith("- ") or line.startswith("* ") or line.startswith(" - ") or line.startswith(" * ")):
1764
- # Break at top-level bullet points or headers to keep related indented lines together
1765
- if current_segment:
1766
- segments.append(current_segment)
1767
- current_segment = [line]
1768
- else:
1769
- current_segment.append(line)
1770
-
1771
- if current_segment:
1772
- segments.append(current_segment)
1773
-
1774
- # Now pack segments into chunks by total char length
1775
- chunks = []
1776
- current_chunk = []
1777
- current_len = 0
1778
-
1779
- for seg in segments:
1780
- # Estimate length if we add this segment (with newlines)
1781
- seg_text = "\n".join(seg)
1782
- seg_len = len(seg_text) + (1 if current_chunk else 0) # +1 for newline before segment
1783
-
1784
- if seg_len > max_chars:
1785
- # Segment itself is huge; fall back to splitting inside it line-by-line
1786
- for line in seg:
1787
- line_len = len(line) + (1 if current_chunk else 0)
1788
- if current_len + line_len > max_chars and current_chunk:
1789
- chunks.append(current_chunk)
1790
- current_chunk = [line]
1791
- current_len = len(line)
1792
- else:
1793
- current_chunk.append(line)
1794
- current_len += line_len
1795
- continue
1796
-
1797
- if current_len + seg_len > max_chars and current_chunk:
1798
- # Start a new chunk
1799
- chunks.append(current_chunk)
1800
- current_chunk = list(seg)
1801
- current_len = len(seg_text)
1802
- else:
1803
- # Add segment to current chunk
1804
- if current_chunk:
1805
- current_chunk.append("") # ensure a blank line between segments
1806
- current_len += 1
1807
- current_chunk.extend(seg)
1808
- current_len += len(seg_text)
1809
-
1810
- if current_chunk:
1811
- chunks.append(current_chunk)
1812
-
1813
- return chunks