bias-core 0.1.0__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 (234) hide show
  1. bias_core-0.1.0/PKG-INFO +39 -0
  2. bias_core-0.1.0/README.md +69 -0
  3. bias_core-0.1.0/pyproject.toml +55 -0
  4. bias_core-0.1.0/setup.cfg +4 -0
  5. bias_core-0.1.0/src/bias_core/__init__.py +6 -0
  6. bias_core-0.1.0/src/bias_core/admin.py +28 -0
  7. bias_core-0.1.0/src/bias_core/admin_api.py +18 -0
  8. bias_core-0.1.0/src/bias_core/admin_audit_api.py +53 -0
  9. bias_core-0.1.0/src/bias_core/admin_audit_serialization.py +22 -0
  10. bias_core-0.1.0/src/bias_core/admin_auth.py +7 -0
  11. bias_core-0.1.0/src/bias_core/admin_content_api.py +270 -0
  12. bias_core-0.1.0/src/bias_core/admin_extension_detail.py +112 -0
  13. bias_core-0.1.0/src/bias_core/admin_extension_recovery_api.py +56 -0
  14. bias_core-0.1.0/src/bias_core/admin_runtime_summary.py +112 -0
  15. bias_core-0.1.0/src/bias_core/admin_settings_api.py +234 -0
  16. bias_core-0.1.0/src/bias_core/admin_stats_api.py +161 -0
  17. bias_core-0.1.0/src/bias_core/api.py +14 -0
  18. bias_core-0.1.0/src/bias_core/api_errors.py +38 -0
  19. bias_core-0.1.0/src/bias_core/api_runtime.py +122 -0
  20. bias_core-0.1.0/src/bias_core/apps.py +49 -0
  21. bias_core-0.1.0/src/bias_core/audit.py +15 -0
  22. bias_core-0.1.0/src/bias_core/auth.py +18 -0
  23. bias_core-0.1.0/src/bias_core/authorization.py +177 -0
  24. bias_core-0.1.0/src/bias_core/conf/__init__.py +12 -0
  25. bias_core-0.1.0/src/bias_core/conf/bootstrap.py +261 -0
  26. bias_core-0.1.0/src/bias_core/conf/defaults.py +76 -0
  27. bias_core-0.1.0/src/bias_core/conf/extension_discovery.py +26 -0
  28. bias_core-0.1.0/src/bias_core/db.py +27 -0
  29. bias_core-0.1.0/src/bias_core/domain_events.py +75 -0
  30. bias_core-0.1.0/src/bias_core/email_service.py +144 -0
  31. bias_core-0.1.0/src/bias_core/extension_detail/__init__.py +22 -0
  32. bias_core-0.1.0/src/bias_core/extension_detail/_shared.py +8 -0
  33. bias_core-0.1.0/src/bias_core/extension_detail/debug.py +183 -0
  34. bias_core-0.1.0/src/bias_core/extension_detail/forum_domain.py +321 -0
  35. bias_core-0.1.0/src/bias_core/extension_detail/frontend.py +175 -0
  36. bias_core-0.1.0/src/bias_core/extension_detail/models.py +280 -0
  37. bias_core-0.1.0/src/bias_core/extension_detail/orchestrator.py +555 -0
  38. bias_core-0.1.0/src/bias_core/extension_detail/permissions.py +84 -0
  39. bias_core-0.1.0/src/bias_core/extension_detail/resources.py +152 -0
  40. bias_core-0.1.0/src/bias_core/extension_detail/settings_theme.py +132 -0
  41. bias_core-0.1.0/src/bias_core/extension_diagnostics.py +111 -0
  42. bias_core-0.1.0/src/bias_core/extension_django_apps.py +52 -0
  43. bias_core-0.1.0/src/bias_core/extension_serialization.py +15 -0
  44. bias_core-0.1.0/src/bias_core/extension_service.py +249 -0
  45. bias_core-0.1.0/src/bias_core/extension_settings_service.py +197 -0
  46. bias_core-0.1.0/src/bias_core/extension_validation_context.py +21 -0
  47. bias_core-0.1.0/src/bias_core/extensions/__init__.py +206 -0
  48. bias_core-0.1.0/src/bias_core/extensions/admin_actions.py +128 -0
  49. bias_core-0.1.0/src/bias_core/extensions/admin_assets.py +31 -0
  50. bias_core-0.1.0/src/bias_core/extensions/admin_manifest.py +120 -0
  51. bias_core-0.1.0/src/bias_core/extensions/application.py +1042 -0
  52. bias_core-0.1.0/src/bias_core/extensions/application_admin.py +152 -0
  53. bias_core-0.1.0/src/bias_core/extensions/application_event_helpers.py +99 -0
  54. bias_core-0.1.0/src/bias_core/extensions/application_events.py +266 -0
  55. bias_core-0.1.0/src/bias_core/extensions/application_formatting.py +108 -0
  56. bias_core-0.1.0/src/bias_core/extensions/application_forum.py +311 -0
  57. bias_core-0.1.0/src/bias_core/extensions/application_frontend.py +541 -0
  58. bias_core-0.1.0/src/bias_core/extensions/application_models.py +440 -0
  59. bias_core-0.1.0/src/bias_core/extensions/application_policy.py +104 -0
  60. bias_core-0.1.0/src/bias_core/extensions/application_runtime.py +260 -0
  61. bias_core-0.1.0/src/bias_core/extensions/application_search.py +274 -0
  62. bias_core-0.1.0/src/bias_core/extensions/application_services.py +308 -0
  63. bias_core-0.1.0/src/bias_core/extensions/application_types.py +55 -0
  64. bias_core-0.1.0/src/bias_core/extensions/assembly_service.py +25 -0
  65. bias_core-0.1.0/src/bias_core/extensions/assets.py +214 -0
  66. bias_core-0.1.0/src/bias_core/extensions/backend.py +181 -0
  67. bias_core-0.1.0/src/bias_core/extensions/bootstrap.py +80 -0
  68. bias_core-0.1.0/src/bias_core/extensions/bootstrap_state.py +30 -0
  69. bias_core-0.1.0/src/bias_core/extensions/compatibility_guard.py +22 -0
  70. bias_core-0.1.0/src/bias_core/extensions/container.py +120 -0
  71. bias_core-0.1.0/src/bias_core/extensions/contracts.py +104 -0
  72. bias_core-0.1.0/src/bias_core/extensions/definition_assembler.py +106 -0
  73. bias_core-0.1.0/src/bias_core/extensions/discovery.py +39 -0
  74. bias_core-0.1.0/src/bias_core/extensions/event_bus.py +15 -0
  75. bias_core-0.1.0/src/bias_core/extensions/events.py +57 -0
  76. bias_core-0.1.0/src/bias_core/extensions/exceptions.py +29 -0
  77. bias_core-0.1.0/src/bias_core/extensions/extender_helpers.py +101 -0
  78. bias_core-0.1.0/src/bias_core/extensions/extender_values.py +20 -0
  79. bias_core-0.1.0/src/bias_core/extensions/extenders.py +123 -0
  80. bias_core-0.1.0/src/bias_core/extensions/extenders_forum_admin.py +658 -0
  81. bias_core-0.1.0/src/bias_core/extensions/extenders_frontend.py +420 -0
  82. bias_core-0.1.0/src/bias_core/extensions/extenders_model_search.py +500 -0
  83. bias_core-0.1.0/src/bias_core/extensions/extenders_resources.py +765 -0
  84. bias_core-0.1.0/src/bias_core/extensions/extenders_routes_policy.py +320 -0
  85. bias_core-0.1.0/src/bias_core/extensions/extenders_runtime.py +333 -0
  86. bias_core-0.1.0/src/bias_core/extensions/extenders_system.py +415 -0
  87. bias_core-0.1.0/src/bias_core/extensions/extension_runtime.py +360 -0
  88. bias_core-0.1.0/src/bias_core/extensions/formatter_service.py +92 -0
  89. bias_core-0.1.0/src/bias_core/extensions/forum.py +33 -0
  90. bias_core-0.1.0/src/bias_core/extensions/forum_registry_types.py +238 -0
  91. bias_core-0.1.0/src/bias_core/extensions/frontend_compiler.py +700 -0
  92. bias_core-0.1.0/src/bias_core/extensions/frontend_runtime_service.py +393 -0
  93. bias_core-0.1.0/src/bias_core/extensions/frontend_serialization.py +69 -0
  94. bias_core-0.1.0/src/bias_core/extensions/lifecycle.py +235 -0
  95. bias_core-0.1.0/src/bias_core/extensions/locale_service.py +58 -0
  96. bias_core-0.1.0/src/bias_core/extensions/manager.py +1322 -0
  97. bias_core-0.1.0/src/bias_core/extensions/manager_dependencies.py +104 -0
  98. bias_core-0.1.0/src/bias_core/extensions/manager_helpers.py +70 -0
  99. bias_core-0.1.0/src/bias_core/extensions/manager_runtime_actions.py +124 -0
  100. bias_core-0.1.0/src/bias_core/extensions/manifest.py +303 -0
  101. bias_core-0.1.0/src/bias_core/extensions/migration_repository.py +67 -0
  102. bias_core-0.1.0/src/bias_core/extensions/migrations.py +130 -0
  103. bias_core-0.1.0/src/bias_core/extensions/model_references.py +77 -0
  104. bias_core-0.1.0/src/bias_core/extensions/module_extension_view.py +145 -0
  105. bias_core-0.1.0/src/bias_core/extensions/module_loader.py +131 -0
  106. bias_core-0.1.0/src/bias_core/extensions/platform.py +172 -0
  107. bias_core-0.1.0/src/bias_core/extensions/policy_runtime_service.py +146 -0
  108. bias_core-0.1.0/src/bias_core/extensions/product.py +44 -0
  109. bias_core-0.1.0/src/bias_core/extensions/recovery.py +269 -0
  110. bias_core-0.1.0/src/bias_core/extensions/registry.py +35 -0
  111. bias_core-0.1.0/src/bias_core/extensions/runtime.py +340 -0
  112. bias_core-0.1.0/src/bias_core/extensions/runtime_access.py +11 -0
  113. bias_core-0.1.0/src/bias_core/extensions/runtime_core.py +95 -0
  114. bias_core-0.1.0/src/bias_core/extensions/runtime_discussions.py +130 -0
  115. bias_core-0.1.0/src/bias_core/extensions/runtime_event_listeners.py +62 -0
  116. bias_core-0.1.0/src/bias_core/extensions/runtime_models.py +150 -0
  117. bias_core-0.1.0/src/bias_core/extensions/runtime_moderation.py +94 -0
  118. bias_core-0.1.0/src/bias_core/extensions/runtime_notifications.py +36 -0
  119. bias_core-0.1.0/src/bias_core/extensions/runtime_posts.py +202 -0
  120. bias_core-0.1.0/src/bias_core/extensions/runtime_probe.py +5 -0
  121. bias_core-0.1.0/src/bias_core/extensions/runtime_search.py +23 -0
  122. bias_core-0.1.0/src/bias_core/extensions/runtime_service.py +14 -0
  123. bias_core-0.1.0/src/bias_core/extensions/runtime_services.py +80 -0
  124. bias_core-0.1.0/src/bias_core/extensions/runtime_tags.py +99 -0
  125. bias_core-0.1.0/src/bias_core/extensions/runtime_users.py +135 -0
  126. bias_core-0.1.0/src/bias_core/extensions/sdk.py +135 -0
  127. bias_core-0.1.0/src/bias_core/extensions/settings_runtime_service.py +107 -0
  128. bias_core-0.1.0/src/bias_core/extensions/signal_bootstrap.py +5 -0
  129. bias_core-0.1.0/src/bias_core/extensions/signal_runtime.py +168 -0
  130. bias_core-0.1.0/src/bias_core/extensions/site_extenders.py +9 -0
  131. bias_core-0.1.0/src/bias_core/extensions/system_runtime.py +497 -0
  132. bias_core-0.1.0/src/bias_core/extensions/template_loader.py +69 -0
  133. bias_core-0.1.0/src/bias_core/extensions/types.py +755 -0
  134. bias_core-0.1.0/src/bias_core/extensions/validation.py +436 -0
  135. bias_core-0.1.0/src/bias_core/extensions/validation_inspection.py +273 -0
  136. bias_core-0.1.0/src/bias_core/extensions/validation_manifest.py +363 -0
  137. bias_core-0.1.0/src/bias_core/extensions/validation_rules.py +71 -0
  138. bias_core-0.1.0/src/bias_core/extensions/validation_source.py +265 -0
  139. bias_core-0.1.0/src/bias_core/extensions/validation_types.py +63 -0
  140. bias_core-0.1.0/src/bias_core/extensions/version_compatibility.py +87 -0
  141. bias_core-0.1.0/src/bias_core/file_service.py +44 -0
  142. bias_core-0.1.0/src/bias_core/forum_permissions.py +12 -0
  143. bias_core-0.1.0/src/bias_core/forum_registry.py +555 -0
  144. bias_core-0.1.0/src/bias_core/forum_registry_core.py +112 -0
  145. bias_core-0.1.0/src/bias_core/forum_resources.py +48 -0
  146. bias_core-0.1.0/src/bias_core/forum_runtime.py +127 -0
  147. bias_core-0.1.0/src/bias_core/jwt_auth.py +170 -0
  148. bias_core-0.1.0/src/bias_core/link_formatter.py +153 -0
  149. bias_core-0.1.0/src/bias_core/mail_drivers.py +187 -0
  150. bias_core-0.1.0/src/bias_core/management/__init__.py +0 -0
  151. bias_core-0.1.0/src/bias_core/management/command_utils.py +35 -0
  152. bias_core-0.1.0/src/bias_core/management/commands/__init__.py +0 -0
  153. bias_core-0.1.0/src/bias_core/management/commands/build_extension_frontend.py +103 -0
  154. bias_core-0.1.0/src/bias_core/management/commands/clear_runtime_cache.py +25 -0
  155. bias_core-0.1.0/src/bias_core/management/commands/create_extension.py +243 -0
  156. bias_core-0.1.0/src/bias_core/management/commands/doctor.py +39 -0
  157. bias_core-0.1.0/src/bias_core/management/commands/ensure_admin.py +34 -0
  158. bias_core-0.1.0/src/bias_core/management/commands/extension_console.py +77 -0
  159. bias_core-0.1.0/src/bias_core/management/commands/extension_disable.py +13 -0
  160. bias_core-0.1.0/src/bias_core/management/commands/extension_enable.py +16 -0
  161. bias_core-0.1.0/src/bias_core/management/commands/finalize_release.py +69 -0
  162. bias_core-0.1.0/src/bias_core/management/commands/inspect_extensions.py +174 -0
  163. bias_core-0.1.0/src/bias_core/management/commands/install_forum.py +484 -0
  164. bias_core-0.1.0/src/bias_core/management/commands/migrate_extensions.py +179 -0
  165. bias_core-0.1.0/src/bias_core/management/commands/prepare_release.py +135 -0
  166. bias_core-0.1.0/src/bias_core/management/commands/publish_release.py +91 -0
  167. bias_core-0.1.0/src/bias_core/management/commands/sync_extensions.py +21 -0
  168. bias_core-0.1.0/src/bias_core/management/commands/sync_forum_version.py +13 -0
  169. bias_core-0.1.0/src/bias_core/management/commands/upgrade_forum.py +171 -0
  170. bias_core-0.1.0/src/bias_core/management/commands/validate_extensions.py +141 -0
  171. bias_core-0.1.0/src/bias_core/markdown_service.py +183 -0
  172. bias_core-0.1.0/src/bias_core/middleware.py +89 -0
  173. bias_core-0.1.0/src/bias_core/migrations/0001_initial.py +123 -0
  174. bias_core-0.1.0/src/bias_core/migrations/__init__.py +0 -0
  175. bias_core-0.1.0/src/bias_core/models.py +77 -0
  176. bias_core-0.1.0/src/bias_core/online_service.py +209 -0
  177. bias_core-0.1.0/src/bias_core/queue_service.py +253 -0
  178. bias_core-0.1.0/src/bias_core/realtime/__init__.py +3 -0
  179. bias_core-0.1.0/src/bias_core/realtime/routing.py +1 -0
  180. bias_core-0.1.0/src/bias_core/registry/__init__.py +0 -0
  181. bias_core-0.1.0/src/bias_core/registry/definition_mutator.py +295 -0
  182. bias_core-0.1.0/src/bias_core/registry/endpoint_context.py +423 -0
  183. bias_core-0.1.0/src/bias_core/registry/jsonapi_serializer.py +162 -0
  184. bias_core-0.1.0/src/bias_core/registry/preload_planner.py +313 -0
  185. bias_core-0.1.0/src/bias_core/registry/resource_validator.py +340 -0
  186. bias_core-0.1.0/src/bias_core/registry/search_bridge.py +190 -0
  187. bias_core-0.1.0/src/bias_core/release.py +110 -0
  188. bias_core-0.1.0/src/bias_core/resource_api.py +72 -0
  189. bias_core-0.1.0/src/bias_core/resource_context.py +228 -0
  190. bias_core-0.1.0/src/bias_core/resource_conversion.py +140 -0
  191. bias_core-0.1.0/src/bias_core/resource_definitions.py +175 -0
  192. bias_core-0.1.0/src/bias_core/resource_dispatcher.py +156 -0
  193. bias_core-0.1.0/src/bias_core/resource_endpoint_runner.py +472 -0
  194. bias_core-0.1.0/src/bias_core/resource_errors.py +105 -0
  195. bias_core-0.1.0/src/bias_core/resource_objects.py +857 -0
  196. bias_core-0.1.0/src/bias_core/resource_registry.py +1694 -0
  197. bias_core-0.1.0/src/bias_core/resource_routes.py +205 -0
  198. bias_core-0.1.0/src/bias_core/resource_runtime_api.py +50 -0
  199. bias_core-0.1.0/src/bias_core/resource_search.py +613 -0
  200. bias_core-0.1.0/src/bias_core/resource_serializer.py +340 -0
  201. bias_core-0.1.0/src/bias_core/resource_validation.py +302 -0
  202. bias_core-0.1.0/src/bias_core/resources/__init__.py +8 -0
  203. bias_core-0.1.0/src/bias_core/resources/registry.py +22 -0
  204. bias_core-0.1.0/src/bias_core/routing.py +22 -0
  205. bias_core-0.1.0/src/bias_core/runtime_checks.py +233 -0
  206. bias_core-0.1.0/src/bias_core/runtime_diagnostics.py +524 -0
  207. bias_core-0.1.0/src/bias_core/runtime_state.py +68 -0
  208. bias_core-0.1.0/src/bias_core/schemas.py +23 -0
  209. bias_core-0.1.0/src/bias_core/search_index_service.py +122 -0
  210. bias_core-0.1.0/src/bias_core/secret_validation.py +92 -0
  211. bias_core-0.1.0/src/bias_core/services.py +34 -0
  212. bias_core-0.1.0/src/bias_core/settings_service.py +591 -0
  213. bias_core-0.1.0/src/bias_core/startup_guard.py +33 -0
  214. bias_core-0.1.0/src/bias_core/storage_service.py +374 -0
  215. bias_core-0.1.0/src/bias_core/test_runner.py +61 -0
  216. bias_core-0.1.0/src/bias_core/version.py +1 -0
  217. bias_core-0.1.0/src/bias_core/visibility.py +21 -0
  218. bias_core-0.1.0/src/bias_core/websocket_auth.py +85 -0
  219. bias_core-0.1.0/src/bias_core.egg-info/PKG-INFO +39 -0
  220. bias_core-0.1.0/src/bias_core.egg-info/SOURCES.txt +232 -0
  221. bias_core-0.1.0/src/bias_core.egg-info/dependency_links.txt +1 -0
  222. bias_core-0.1.0/src/bias_core.egg-info/requires.txt +37 -0
  223. bias_core-0.1.0/src/bias_core.egg-info/top_level.txt +1 -0
  224. bias_core-0.1.0/tests/test_admin_audit.py +64 -0
  225. bias_core-0.1.0/tests/test_admin_auth.py +20 -0
  226. bias_core-0.1.0/tests/test_admin_dashboard.py +400 -0
  227. bias_core-0.1.0/tests/test_bootstrap_config.py +119 -0
  228. bias_core-0.1.0/tests/test_domain_event_registry.py +53 -0
  229. bias_core-0.1.0/tests/test_domain_events.py +95 -0
  230. bias_core-0.1.0/tests/test_extension_diagnostics.py +113 -0
  231. bias_core-0.1.0/tests/test_health.py +54 -0
  232. bias_core-0.1.0/tests/test_secret_validation.py +87 -0
  233. bias_core-0.1.0/tests/test_system.py +18 -0
  234. bias_core-0.1.0/tests/test_ws_auth.py +36 -0
@@ -0,0 +1,39 @@
1
+ Metadata-Version: 2.4
2
+ Name: bias-core
3
+ Version: 0.1.0
4
+ Summary: Bias forum backend core platform
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: Django<5.1,>=5.0
7
+ Requires-Dist: django-ninja<1.3,>=1.2
8
+ Requires-Dist: django-ninja-jwt<5.4,>=5.3
9
+ Requires-Dist: django-ninja-extra<0.22,>=0.21
10
+ Requires-Dist: channels<4.1,>=4.0
11
+ Requires-Dist: channels-redis<4.3,>=4.2
12
+ Requires-Dist: celery<5.4,>=5.3
13
+ Requires-Dist: redis<5.1,>=5.0
14
+ Requires-Dist: django-redis<5.5,>=5.4
15
+ Requires-Dist: pydantic<2.7,>=2.6
16
+ Requires-Dist: markdown<3.6,>=3.5
17
+ Requires-Dist: bleach<6.2,>=6.1
18
+ Requires-Dist: pymdown-extensions<10.8,>=10.7
19
+ Requires-Dist: python-dateutil<3,>=2.9
20
+ Requires-Dist: django-cors-headers<4.4,>=4.3
21
+ Requires-Dist: django-extensions<3.3,>=3.2
22
+ Requires-Dist: python-dotenv<1.1,>=1.0
23
+ Requires-Dist: jieba<0.43,>=0.42
24
+ Requires-Dist: httpx<0.28,>=0.27
25
+ Requires-Dist: Pillow<11,>=10.2
26
+ Provides-Extra: postgres
27
+ Requires-Dist: psycopg2-binary<3,>=2.9; extra == "postgres"
28
+ Provides-Extra: storage
29
+ Requires-Dist: boto3<2,>=1.34; extra == "storage"
30
+ Requires-Dist: oss2<3,>=2.18; extra == "storage"
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest<8.2,>=8.1; extra == "dev"
33
+ Requires-Dist: pytest-django<4.9,>=4.8; extra == "dev"
34
+ Requires-Dist: pytest-cov<4.2,>=4.1; extra == "dev"
35
+ Requires-Dist: import-linter<3,>=2.11; extra == "dev"
36
+ Requires-Dist: factory-boy<3.4,>=3.3; extra == "dev"
37
+ Requires-Dist: daphne<4.2,>=4.1; extra == "dev"
38
+ Requires-Dist: gunicorn<23,>=22.0; extra == "dev"
39
+ Requires-Dist: uvicorn<0.31,>=0.30; extra == "dev"
@@ -0,0 +1,69 @@
1
+ # Bias Core
2
+
3
+ Bias forum 后端核心平台包。
4
+
5
+ `bias-core` 是独立于网站工程的 Python 包,提供 Django app、数据模型、扩展宿主、资源 API 运行时和平台服务。
6
+
7
+ ## 安装
8
+
9
+ ```bash
10
+ pip install bias-core
11
+ ```
12
+
13
+ ## 开发
14
+
15
+ ```bash
16
+ # 克隆后安装
17
+ pip install -e ".[dev]"
18
+
19
+ # 运行测试
20
+ pytest
21
+
22
+ # 构建
23
+ python -m build
24
+ ```
25
+
26
+ ## 架构
27
+
28
+ ```
29
+ bias_core
30
+ ├─ conf/ # 配置引导和扩展发现
31
+ ├─ extensions/ # 扩展宿主 + 公共 SDK(第三方扩展唯一依赖)
32
+ ├─ resources/ # 资源注册表和 JSON:API 运行时
33
+ ├─ services/ # 平台服务
34
+ ├─ api/ # API 应用构建器
35
+ ├─ realtime/ # WebSocket/实时通信支撑
36
+ └─ management/ # 管理命令(doctor、sync_extensions 等)
37
+ ```
38
+
39
+ ## 扩展开发
40
+
41
+ ```python
42
+ from bias_core.extensions import SettingsExtender, setting_field
43
+
44
+ def extend():
45
+ return [
46
+ SettingsExtender(
47
+ fields=[
48
+ setting_field(
49
+ key="my_ext.enabled",
50
+ type="boolean",
51
+ label="Enable feature",
52
+ default=True,
53
+ )
54
+ ]
55
+ )
56
+ ]
57
+ ```
58
+
59
+ ## 依赖
60
+
61
+ - Python >= 3.11
62
+ - Django >= 5.0
63
+ - django-ninja >= 1.2
64
+ - Channels >= 4.0
65
+ - Celery >= 5.3
66
+
67
+ ## 许可
68
+
69
+ MIT
@@ -0,0 +1,55 @@
1
+ [project]
2
+ name = "bias-core"
3
+ version = "0.1.0"
4
+ description = "Bias forum backend core platform"
5
+ requires-python = ">=3.11"
6
+
7
+ dependencies = [
8
+ "Django>=5.0,<5.1",
9
+ "django-ninja>=1.2,<1.3",
10
+ "django-ninja-jwt>=5.3,<5.4",
11
+ "django-ninja-extra>=0.21,<0.22",
12
+ "channels>=4.0,<4.1",
13
+ "channels-redis>=4.2,<4.3",
14
+ "celery>=5.3,<5.4",
15
+ "redis>=5.0,<5.1",
16
+ "django-redis>=5.4,<5.5",
17
+ "pydantic>=2.6,<2.7",
18
+ "markdown>=3.5,<3.6",
19
+ "bleach>=6.1,<6.2",
20
+ "pymdown-extensions>=10.7,<10.8",
21
+ "python-dateutil>=2.9,<3",
22
+ "django-cors-headers>=4.3,<4.4",
23
+ "django-extensions>=3.2,<3.3",
24
+ "python-dotenv>=1.0,<1.1",
25
+ "jieba>=0.42,<0.43",
26
+ "httpx>=0.27,<0.28",
27
+ "Pillow>=10.2,<11",
28
+ ]
29
+
30
+ [project.optional-dependencies]
31
+ postgres = ["psycopg2-binary>=2.9,<3"]
32
+ storage = ["boto3>=1.34,<2", "oss2>=2.18,<3"]
33
+ dev = [
34
+ "pytest>=8.1,<8.2",
35
+ "pytest-django>=4.8,<4.9",
36
+ "pytest-cov>=4.1,<4.2",
37
+ "import-linter>=2.11,<3",
38
+ "factory-boy>=3.3,<3.4",
39
+ "daphne>=4.1,<4.2",
40
+ "gunicorn>=22.0,<23",
41
+ "uvicorn>=0.30,<0.31",
42
+ ]
43
+
44
+ [tool.setuptools.packages.find]
45
+ where = ["src"]
46
+
47
+ [tool.pytest.ini_options]
48
+ DJANGO_SETTINGS_MODULE = "tests.settings"
49
+ python_files = "tests.py test_*.py *_tests.py"
50
+ testpaths = ["tests"]
51
+ addopts = "--tb=short -v"
52
+ filterwarnings = [
53
+ "ignore::DeprecationWarning:pydantic",
54
+ "ignore::UserWarning:django.test.utils",
55
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,6 @@
1
+ from bias_core.version import APP_VERSION
2
+
3
+ default_app_config = "bias_core.apps.CoreConfig"
4
+
5
+ __version__ = APP_VERSION
6
+ __all__ = ["__version__", "default_app_config"]
@@ -0,0 +1,28 @@
1
+ from django.contrib import admin
2
+
3
+ from bias_core.models import AuditLog, Setting
4
+
5
+
6
+ @admin.register(Setting)
7
+ class SettingAdmin(admin.ModelAdmin):
8
+ list_display = ["key", "updated_at"]
9
+ search_fields = ["key", "value"]
10
+ readonly_fields = ["created_at", "updated_at"]
11
+
12
+
13
+ @admin.register(AuditLog)
14
+ class AuditLogAdmin(admin.ModelAdmin):
15
+ list_display = ["created_at", "user", "action", "target_type", "target_id", "ip_address"]
16
+ list_filter = ["action", "target_type", "created_at"]
17
+ search_fields = ["action", "target_type", "target_id", "user__username"]
18
+ readonly_fields = [
19
+ "user",
20
+ "action",
21
+ "target_type",
22
+ "target_id",
23
+ "ip_address",
24
+ "user_agent",
25
+ "data",
26
+ "created_at",
27
+ ]
28
+
@@ -0,0 +1,18 @@
1
+ """管理后台 API 路由聚合。"""
2
+ from ninja import Router
3
+
4
+ from bias_core.admin_audit_api import router as audit_router
5
+ from bias_core.admin_content_api import router as content_router
6
+ from bias_core.admin_extension_recovery_api import router as extension_recovery_router
7
+ from bias_core.admin_settings_api import router as settings_router
8
+ from bias_core.admin_stats_api import router as stats_router
9
+
10
+
11
+ router = Router()
12
+ router.add_router("", audit_router)
13
+ router.add_router("", content_router)
14
+ router.add_router("", extension_recovery_router)
15
+ router.add_router("", settings_router)
16
+ router.add_router("", stats_router)
17
+
18
+
@@ -0,0 +1,53 @@
1
+ from __future__ import annotations
2
+
3
+ from ninja import Router
4
+
5
+ from bias_core.admin_audit_serialization import serialize_audit_log
6
+ from bias_core.admin_auth import require_staff
7
+ from bias_core.jwt_auth import AccessTokenAuth
8
+ from bias_core.models import AuditLog
9
+ from bias_core.services import PaginationService
10
+
11
+
12
+ router = Router()
13
+
14
+
15
+ @router.get("/audit-logs", auth=AccessTokenAuth(), tags=["Admin"])
16
+ def list_audit_logs(
17
+ request,
18
+ page: int = 1,
19
+ limit: int = 20,
20
+ action: str = "",
21
+ target_type: str = "",
22
+ user_id: int = None,
23
+ ):
24
+ denied = require_staff(request)
25
+ if denied:
26
+ return denied
27
+
28
+ page, limit = PaginationService.normalize(page, limit)
29
+ queryset = (
30
+ AuditLog.objects.select_related("user")
31
+ .filter(action__startswith="admin.")
32
+ .order_by("-created_at", "-id")
33
+ )
34
+
35
+ if action:
36
+ queryset = queryset.filter(action=action)
37
+ if target_type:
38
+ queryset = queryset.filter(target_type=target_type)
39
+ if user_id:
40
+ queryset = queryset.filter(user_id=user_id)
41
+
42
+ total = queryset.count()
43
+ offset = (page - 1) * limit
44
+ logs = queryset[offset:offset + limit]
45
+
46
+ return {
47
+ "total": total,
48
+ "page": page,
49
+ "limit": limit,
50
+ "data": [serialize_audit_log(log) for log in logs],
51
+ }
52
+
53
+
@@ -0,0 +1,22 @@
1
+ from __future__ import annotations
2
+
3
+ from bias_core.models import AuditLog
4
+
5
+
6
+ def serialize_audit_log(log: AuditLog) -> dict:
7
+ return {
8
+ "id": log.id,
9
+ "action": log.action,
10
+ "target_type": log.target_type,
11
+ "target_id": log.target_id,
12
+ "ip_address": log.ip_address,
13
+ "user_agent": log.user_agent,
14
+ "data": log.data,
15
+ "created_at": log.created_at,
16
+ "user": {
17
+ "id": log.user.id,
18
+ "username": log.user.username,
19
+ "display_name": log.user.username,
20
+ } if log.user else None,
21
+ }
22
+
@@ -0,0 +1,7 @@
1
+ from bias_core.api_errors import api_error
2
+
3
+
4
+ def require_staff(request):
5
+ if not getattr(request, "auth", None) or not request.auth.is_staff:
6
+ return api_error("需要管理员权限", status=403)
7
+ return None
@@ -0,0 +1,270 @@
1
+ import logging
2
+
3
+ from ninja import Body, Router
4
+
5
+ from bias_core.api_errors import api_error
6
+ from bias_core.admin_auth import require_staff
7
+ from bias_core.extensions.exceptions import ExtensionNotFoundError, ExtensionStateError
8
+ from bias_core.extensions.registry import get_extension_registry
9
+ from bias_core.extension_service import ExtensionService
10
+ from bias_core.extension_settings_service import get_extension_settings, serialize_extension_settings_schema, save_extension_settings
11
+ from bias_core.extensions.frontend_compiler import inspect_extension_frontend_output_manifest
12
+ from bias_core.audit import log_admin_action
13
+ from bias_core.jwt_auth import AccessTokenAuth
14
+ from bias_core.admin_extension_detail import (
15
+ _serialize_admin_extension,
16
+ _serialize_admin_extension_action_payload,
17
+ _serialize_admin_extensions_payload,
18
+ serialize_admin_extension,
19
+ serialize_admin_extensions_payload,
20
+ )
21
+
22
+
23
+ router = Router()
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ _require_staff = require_staff
28
+
29
+
30
+ @router.get("/extensions", auth=AccessTokenAuth(), tags=["Admin"])
31
+ def list_admin_extensions(request):
32
+ denied = _require_staff(request)
33
+ if denied:
34
+ return denied
35
+
36
+ summary = str(request.GET.get("summary") or "").strip().lower() in {"1", "true", "yes", "on"}
37
+ return _serialize_admin_extensions_payload(get_extension_registry().get_extensions(), summary=summary)
38
+
39
+
40
+ @router.post("/extensions/sync", auth=AccessTokenAuth(), tags=["Admin"])
41
+ def sync_admin_extensions(request, payload: dict = Body(default={})):
42
+ denied = _require_staff(request)
43
+ if denied:
44
+ return denied
45
+
46
+ prune_missing = bool(dict(payload or {}).get("prune_missing", True))
47
+ ExtensionService.sync_extension_packages(
48
+ prune_missing=prune_missing,
49
+ actor=request.auth,
50
+ request=request,
51
+ )
52
+ return _serialize_admin_extensions_payload(get_extension_registry().get_extensions())
53
+
54
+
55
+ @router.post("/extensions/sync-order", auth=AccessTokenAuth(), tags=["Admin"])
56
+ def sync_admin_extension_order(request):
57
+ denied = _require_staff(request)
58
+ if denied:
59
+ return denied
60
+
61
+ try:
62
+ ExtensionService.sync_enabled_extension_order(
63
+ actor=request.auth,
64
+ request=request,
65
+ )
66
+ except ExtensionStateError as exc:
67
+ return api_error(str(exc), status=409, code=exc.code, field_errors=exc.details)
68
+ return _serialize_admin_extensions_payload(get_extension_registry().get_extensions())
69
+
70
+
71
+ @router.post("/extensions/rebuild-frontend", auth=AccessTokenAuth(), tags=["Admin"])
72
+ def rebuild_admin_extension_frontend(request, payload: dict = Body(default={})):
73
+ denied = _require_staff(request)
74
+ if denied:
75
+ return denied
76
+
77
+ options = dict(payload or {})
78
+ result = ExtensionService.rebuild_extension_frontend_assets(
79
+ run_build=bool(options.get("run_build", True)),
80
+ include_disabled=bool(options.get("include_disabled", False)),
81
+ publish=bool(options.get("publish", False)),
82
+ actor=request.auth,
83
+ request=request,
84
+ )
85
+ status = str(result.get("status") or "")
86
+ if status and status != "ok":
87
+ return api_error(
88
+ str(result.get("message") or "扩展前端资产重建失败"),
89
+ status=409,
90
+ code="extension_frontend_rebuild_failed",
91
+ field_errors=result,
92
+ )
93
+ return {
94
+ **_serialize_admin_extensions_payload(get_extension_registry().get_extensions()),
95
+ "frontend_rebuild": result,
96
+ }
97
+
98
+
99
+ @router.get("/extensions/{extension_id}", auth=AccessTokenAuth(), tags=["Admin"])
100
+ def get_admin_extension(request, extension_id: str):
101
+ denied = _require_staff(request)
102
+ if denied:
103
+ return denied
104
+
105
+ try:
106
+ extension = get_extension_registry().get_extension(extension_id)
107
+ except ExtensionNotFoundError:
108
+ return api_error("扩展不存在", status=404, code="extension_not_found")
109
+ frontend_output_manifest = inspect_extension_frontend_output_manifest()
110
+ return {
111
+ "extension": _serialize_admin_extension(
112
+ extension,
113
+ include_permission_details=True,
114
+ frontend_output_manifest=frontend_output_manifest,
115
+ ),
116
+ }
117
+
118
+
119
+ @router.get("/extensions/{extension_id}/settings", auth=AccessTokenAuth(), tags=["Admin"])
120
+ def get_admin_extension_settings(request, extension_id: str):
121
+ denied = _require_staff(request)
122
+ if denied:
123
+ return denied
124
+
125
+ try:
126
+ extension = get_extension_registry().get_extension(extension_id)
127
+ return {
128
+ "extension_id": extension.id,
129
+ "schema": serialize_extension_settings_schema(extension.id),
130
+ "settings": get_extension_settings(extension.id),
131
+ }
132
+ except ExtensionNotFoundError:
133
+ return api_error("扩展不存在", status=404, code="extension_not_found")
134
+
135
+
136
+ @router.post("/extensions/{extension_id}/settings", auth=AccessTokenAuth(), tags=["Admin"])
137
+ def save_admin_extension_settings(request, extension_id: str, payload: dict = Body(...)):
138
+ denied = _require_staff(request)
139
+ if denied:
140
+ return denied
141
+
142
+ try:
143
+ extension = get_extension_registry().get_extension(extension_id)
144
+ settings_data = save_extension_settings(extension.id, payload)
145
+ log_admin_action(
146
+ request,
147
+ "admin.extension.settings.update",
148
+ target_type="extension",
149
+ data={
150
+ "extension_id": extension.id,
151
+ "keys": sorted(payload.keys()),
152
+ },
153
+ )
154
+ return {
155
+ "message": "扩展设置保存成功",
156
+ "extension_id": extension.id,
157
+ "settings": settings_data,
158
+ }
159
+ except ExtensionNotFoundError:
160
+ return api_error("扩展不存在", status=404, code="extension_not_found")
161
+ except ExtensionStateError as exc:
162
+ return api_error(str(exc), status=409, code=exc.code, field_errors=exc.details)
163
+
164
+
165
+ @router.post("/extensions/{extension_id}/enable", auth=AccessTokenAuth(), tags=["Admin"])
166
+ def enable_admin_extension(request, extension_id: str):
167
+ denied = _require_staff(request)
168
+ if denied:
169
+ return denied
170
+
171
+ try:
172
+ extension = ExtensionService.set_extension_enabled(
173
+ extension_id,
174
+ True,
175
+ actor=request.auth,
176
+ request=request,
177
+ )
178
+ except ExtensionStateError as exc:
179
+ return api_error(str(exc), status=409, code=exc.code, field_errors=exc.details)
180
+ return _serialize_admin_extension_action_payload(extension)
181
+
182
+
183
+ @router.post("/extensions/{extension_id}/install", auth=AccessTokenAuth(), tags=["Admin"])
184
+ def install_admin_extension(request, extension_id: str):
185
+ denied = _require_staff(request)
186
+ if denied:
187
+ return denied
188
+
189
+ try:
190
+ extension = ExtensionService.install_extension(
191
+ extension_id,
192
+ actor=request.auth,
193
+ request=request,
194
+ )
195
+ except ExtensionStateError as exc:
196
+ return api_error(str(exc), status=409, code=exc.code, field_errors=exc.details)
197
+ return _serialize_admin_extension_action_payload(extension)
198
+
199
+
200
+ @router.post("/extensions/{extension_id}/runtime-hooks/{hook_name}", auth=AccessTokenAuth(), tags=["Admin"])
201
+ def run_admin_extension_runtime_hook(request, extension_id: str, hook_name: str):
202
+ denied = _require_staff(request)
203
+ if denied:
204
+ return denied
205
+
206
+ try:
207
+ extension = ExtensionService.run_extension_runtime_hook(
208
+ extension_id,
209
+ hook_name,
210
+ actor=request.auth,
211
+ request=request,
212
+ )
213
+ except ExtensionStateError as exc:
214
+ return api_error(str(exc), status=409, code=exc.code, field_errors=exc.details)
215
+ return _serialize_admin_extension_action_payload(extension)
216
+
217
+
218
+ @router.post("/extensions/{extension_id}/migrations", auth=AccessTokenAuth(), tags=["Admin"])
219
+ def run_admin_extension_migrations(request, extension_id: str):
220
+ denied = _require_staff(request)
221
+ if denied:
222
+ return denied
223
+
224
+ try:
225
+ extension = ExtensionService.run_extension_migrations(
226
+ extension_id,
227
+ actor=request.auth,
228
+ request=request,
229
+ )
230
+ except ExtensionStateError as exc:
231
+ return api_error(str(exc), status=409, code=exc.code, field_errors=exc.details)
232
+ return _serialize_admin_extension_action_payload(extension)
233
+
234
+
235
+ @router.post("/extensions/{extension_id}/disable", auth=AccessTokenAuth(), tags=["Admin"])
236
+ def disable_admin_extension(request, extension_id: str):
237
+ denied = _require_staff(request)
238
+ if denied:
239
+ return denied
240
+
241
+ try:
242
+ extension = ExtensionService.set_extension_enabled(
243
+ extension_id,
244
+ False,
245
+ actor=request.auth,
246
+ request=request,
247
+ )
248
+ except ExtensionStateError as exc:
249
+ return api_error(str(exc), status=409, code=exc.code, field_errors=exc.details)
250
+ return _serialize_admin_extension_action_payload(extension)
251
+
252
+
253
+ @router.post("/extensions/{extension_id}/uninstall", auth=AccessTokenAuth(), tags=["Admin"])
254
+ def uninstall_admin_extension(request, extension_id: str):
255
+ denied = _require_staff(request)
256
+ if denied:
257
+ return denied
258
+
259
+ try:
260
+ extension = ExtensionService.uninstall_extension(
261
+ extension_id,
262
+ actor=request.auth,
263
+ request=request,
264
+ )
265
+ except ExtensionStateError as exc:
266
+ return api_error(str(exc), status=409, code=exc.code, field_errors=exc.details)
267
+ return _serialize_admin_extension_action_payload(extension)
268
+
269
+
270
+
@@ -0,0 +1,112 @@
1
+ """
2
+ Extension detail serialization.
3
+
4
+ This file is a re-export shim migrated to apps/core/extension_detail/.
5
+ Import from bias_core.extension_detail directly.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ from bias_core.extension_detail.orchestrator import (
10
+ serialize_admin_extension,
11
+ serialize_admin_extensions_payload,
12
+ )
13
+ from bias_core.extension_detail.orchestrator import ( # noqa: F401
14
+ _serialize_admin_extension,
15
+ _serialize_admin_extension_summary,
16
+ _serialize_admin_extensions_payload,
17
+ _serialize_admin_extension_action_payload,
18
+ _build_default_extension_admin_actions,
19
+ _serialize_extension_admin_actions,
20
+ _resolve_extension_runtime_record,
21
+ _serialize_extension_recovery_status,
22
+ _resolve_api_stability_label,
23
+ _resolve_distribution_channel_label,
24
+ _build_extension_capability_summary,
25
+ _serialize_extension_backend_hooks,
26
+ )
27
+
28
+ from bias_core.extension_detail.models import ( # noqa: F401
29
+ _build_extension_model_definitions,
30
+ _build_extension_owned_models,
31
+ _build_extension_model_ownership_audit,
32
+ _build_extension_model_relations,
33
+ _build_extension_model_visibility,
34
+ _resolve_display_model,
35
+ _model_name,
36
+ _model_label,
37
+ _model_module,
38
+ _model_app_label,
39
+ _extension_app_label,
40
+ _extension_app_label_source,
41
+ _model_db_table,
42
+ _model_storage_origin,
43
+ _model_package_migration_required,
44
+ _model_app_label_migration_required,
45
+ _model_migration_risk,
46
+ _model_migration_recommended_steps,
47
+ _build_model_app_label_migration_item,
48
+ _serialize_extension_migration_execution,
49
+ _serialize_extension_migration_plan,
50
+ )
51
+
52
+ from bias_core.extension_detail.resources import ( # noqa: F401
53
+ _build_extension_resource_definitions,
54
+ _build_extension_resource_relationships,
55
+ _build_extension_resource_endpoints,
56
+ _build_extension_resource_sorts,
57
+ _build_extension_resource_filters,
58
+ _build_extension_resource_fields,
59
+ _build_extension_search_drivers,
60
+ _build_extension_search_filters,
61
+ )
62
+
63
+ from bias_core.extension_detail.forum_domain import ( # noqa: F401
64
+ _build_extension_discussion_list_filters,
65
+ _build_extension_discussion_sorts,
66
+ _build_extension_post_types,
67
+ _build_extension_post_lifecycle,
68
+ _build_extension_notification_types,
69
+ _build_extension_user_preferences,
70
+ _build_extension_event_listeners,
71
+ _build_extension_realtime_broadcasts,
72
+ _build_extension_language_packs,
73
+ _build_extension_delivery_assets,
74
+ )
75
+
76
+ from bias_core.extension_detail.permissions import ( # noqa: F401
77
+ _build_extension_permission_sections,
78
+ _build_extension_permission_summary,
79
+ _flatten_extension_permissions,
80
+ _build_extension_permission_modules,
81
+ _build_extension_admin_page_details,
82
+ )
83
+
84
+ from bias_core.extension_detail.frontend import ( # noqa: F401
85
+ _build_extension_frontend_routes,
86
+ _build_extension_frontend_document,
87
+ _resolve_extension_frontend_admin_entry,
88
+ _resolve_extension_frontend_forum_entry,
89
+ _resolve_extension_frontend_outputs,
90
+ _resolve_extension_settings_pages,
91
+ _resolve_extension_permissions_pages,
92
+ _resolve_extension_operations_pages,
93
+ _build_runtime_surface_view,
94
+ _serialize_extension_runtime_rebuild_state,
95
+ _serialize_extension_frontend_asset_state_for_extension,
96
+ )
97
+
98
+ from bias_core.extension_detail.settings_theme import ( # noqa: F401
99
+ _build_extension_settings_runtime,
100
+ _build_extension_theme_runtime,
101
+ _build_extension_system_hooks,
102
+ )
103
+
104
+ from bias_core.extension_detail.debug import ( # noqa: F401
105
+ _build_extension_debug_info,
106
+ _serialize_debug_value,
107
+ )
108
+
109
+ from bias_core.extension_detail._shared import ( # noqa: F401
110
+ _serialize_callable_or_value,
111
+ )
112
+