django-whiteneuron 0.3.1.2__tar.gz → 0.4.0.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 (265) hide show
  1. django_whiteneuron-0.4.0.0/PKG-INFO +563 -0
  2. django_whiteneuron-0.4.0.0/README.md +477 -0
  3. django_whiteneuron-0.4.0.0/django_whiteneuron.egg-info/PKG-INFO +563 -0
  4. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/django_whiteneuron.egg-info/SOURCES.txt +54 -12
  5. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/django_whiteneuron.egg-info/requires.txt +6 -5
  6. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/pyproject.toml +12 -11
  7. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/admin.py +188 -49
  8. django_whiteneuron-0.4.0.0/whiteneuron/base/asgi.py +39 -0
  9. django_whiteneuron-0.4.0.0/whiteneuron/base/filters.py +55 -0
  10. django_whiteneuron-0.4.0.0/whiteneuron/base/html_sanitize.py +65 -0
  11. django_whiteneuron-0.4.0.0/whiteneuron/base/management/commands/cleanup_old_activities.py +95 -0
  12. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/management/commands/init_admin.py +1 -0
  13. django_whiteneuron-0.4.0.0/whiteneuron/base/management/commands/update_visit_profiles.py +91 -0
  14. django_whiteneuron-0.4.0.0/whiteneuron/base/middleware.py +710 -0
  15. django_whiteneuron-0.4.0.0/whiteneuron/base/migrations/0018_user_uuid.py +32 -0
  16. django_whiteneuron-0.4.0.0/whiteneuron/base/migrations/0019_alter_user_uuid.py +19 -0
  17. django_whiteneuron-0.4.0.0/whiteneuron/base/migrations/0020_add_visit_profile_and_fk_fields.py +40 -0
  18. django_whiteneuron-0.4.0.0/whiteneuron/base/migrations/0021_populate_visit_profiles.py +64 -0
  19. django_whiteneuron-0.4.0.0/whiteneuron/base/migrations/0022_remove_duplicate_visit_profiles.py +61 -0
  20. django_whiteneuron-0.4.0.0/whiteneuron/base/migrations/0023_remove_useractivity_ip_address_and_more.py +41 -0
  21. django_whiteneuron-0.4.0.0/whiteneuron/base/migrations/0024_alter_visitprofile_user_agent_to_charfield.py +18 -0
  22. django_whiteneuron-0.4.0.0/whiteneuron/base/migrations/0025_alter_anonymousactivity_options_and_more.py +21 -0
  23. django_whiteneuron-0.4.0.0/whiteneuron/base/migrations/0026_alter_anonymousactivity_profile_and_more.py +24 -0
  24. django_whiteneuron-0.4.0.0/whiteneuron/base/migrations/0027_alter_anonymousactivity_method_and_more.py +23 -0
  25. django_whiteneuron-0.4.0.0/whiteneuron/base/migrations/0028_perf_indexes.py +25 -0
  26. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/modeladmin.py +232 -157
  27. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/models.py +332 -236
  28. django_whiteneuron-0.4.0.0/whiteneuron/base/queue.py +39 -0
  29. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/settings.py +142 -70
  30. django_whiteneuron-0.4.0.0/whiteneuron/base/tasks.py +49 -0
  31. django_whiteneuron-0.4.0.0/whiteneuron/base/templatetags/wn_theme.py +24 -0
  32. django_whiteneuron-0.4.0.0/whiteneuron/base/testing.py +9 -0
  33. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/tests.py +1 -1
  34. django_whiteneuron-0.4.0.0/whiteneuron/base/tests_regressions.py +371 -0
  35. django_whiteneuron-0.4.0.0/whiteneuron/base/themes.py +39 -0
  36. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/urls.py +3 -2
  37. django_whiteneuron-0.4.0.0/whiteneuron/base/urls_testing.py +13 -0
  38. django_whiteneuron-0.4.0.0/whiteneuron/base/utils.py +242 -0
  39. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/views.py +33 -3
  40. django_whiteneuron-0.4.0.0/whiteneuron/base/widgets.py +17 -0
  41. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/contrib/wn_import_export/admin.py +22 -15
  42. django_whiteneuron-0.4.0.0/whiteneuron/contrib/wn_import_export/tasks.py +49 -0
  43. django_whiteneuron-0.4.0.0/whiteneuron/contrib/wn_modeltranslation/admin.py +36 -0
  44. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/contrib/wn_modeltranslation/utils.py +9 -9
  45. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/dashboard/views.py +128 -115
  46. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/admin.py +16 -0
  47. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/urls.py +16 -2
  48. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/admin.py +75 -13
  49. django_whiteneuron-0.4.0.0/whiteneuron/file_management/migrations/0005_alter_excelfile_file_alter_excelfile_title_and_more.py +33 -0
  50. django_whiteneuron-0.4.0.0/whiteneuron/file_management/migrations/0006_excelfile_is_public_pdffile_is_public.py +23 -0
  51. django_whiteneuron-0.4.0.0/whiteneuron/file_management/migrations/0007_htmlfile.py +41 -0
  52. django_whiteneuron-0.4.0.0/whiteneuron/file_management/migrations/0008_excelfile_allowed_groups_excelfile_allowed_users_and_more.py +46 -0
  53. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/models.py +39 -10
  54. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/urls.py +2 -1
  55. django_whiteneuron-0.4.0.0/whiteneuron/file_management/utils.py +11 -0
  56. django_whiteneuron-0.4.0.0/whiteneuron/file_management/views.py +113 -0
  57. django_whiteneuron-0.4.0.0/whiteneuron/locale/vi/LC_MESSAGES/django.mo +0 -0
  58. django_whiteneuron-0.4.0.0/whiteneuron/locale/vi/LC_MESSAGES/django.po +3274 -0
  59. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/admin.py +161 -0
  60. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/apps.py +8 -0
  61. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/collector.py +157 -0
  62. {django_whiteneuron-0.3.1.2/whiteneuron/notification → django_whiteneuron-0.4.0.0/whiteneuron/monitoring}/management/__init__.py +0 -0
  63. {django_whiteneuron-0.3.1.2/whiteneuron/notification → django_whiteneuron-0.4.0.0/whiteneuron/monitoring}/management/commands/__init__.py +0 -0
  64. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/management/commands/monitoring_collector.py +39 -0
  65. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/migrations/0001_initial.py +123 -0
  66. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/models.py +59 -0
  67. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/permissions.py +3 -0
  68. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/stats.py +218 -0
  69. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/tasks.py +17 -0
  70. django_whiteneuron-0.4.0.0/whiteneuron/monitoring/tests.py +130 -0
  71. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/admin.py +94 -68
  72. django_whiteneuron-0.4.0.0/whiteneuron/notification/consumers.py +39 -0
  73. {django_whiteneuron-0.3.1.2/whiteneuron/synchronization/migrations → django_whiteneuron-0.4.0.0/whiteneuron/notification/management}/__init__.py +0 -0
  74. django_whiteneuron-0.4.0.0/whiteneuron/notification/management/commands/__init__.py +0 -0
  75. django_whiteneuron-0.4.0.0/whiteneuron/notification/migrations/0013_perf_indexes.py +28 -0
  76. django_whiteneuron-0.4.0.0/whiteneuron/notification/migrations/__init__.py +0 -0
  77. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/models.py +46 -9
  78. django_whiteneuron-0.4.0.0/whiteneuron/notification/utils.py +25 -0
  79. django_whiteneuron-0.4.0.0/whiteneuron/notification/views.py +29 -0
  80. django_whiteneuron-0.4.0.0/whiteneuron/static/base/css/btn-styles.css +46 -0
  81. django_whiteneuron-0.4.0.0/whiteneuron/static/base/css/loading.css +26 -0
  82. django_whiteneuron-0.4.0.0/whiteneuron/static/base/css/styles.css +2 -0
  83. django_whiteneuron-0.4.0.0/whiteneuron/static/base/forms/js/mdeditor.js +270 -0
  84. django_whiteneuron-0.4.0.0/whiteneuron/static/base/images/logo/LOGO.jpg +0 -0
  85. django_whiteneuron-0.4.0.0/whiteneuron/static/base/images/logo/WhiteNeuron-128.png +0 -0
  86. django_whiteneuron-0.4.0.0/whiteneuron/static/base/images/logo/WhiteNeuron-32.png +0 -0
  87. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/js/loading.js +17 -2
  88. django_whiteneuron-0.4.0.0/whiteneuron/static/base/js/whiteneuron.js +274 -0
  89. django_whiteneuron-0.4.0.0/whiteneuron/static/monitoring/css/dashboard.css +232 -0
  90. django_whiteneuron-0.4.0.0/whiteneuron/static/monitoring/js/dashboard.js +852 -0
  91. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/base/app_change_list.html +2 -2
  92. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/base.html +3 -3
  93. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/change_list.html +1 -1
  94. django_whiteneuron-0.4.0.0/whiteneuron/templates/admin/feedbacks/change_form_feedback_list.html +70 -0
  95. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/grid_view_results.html +3 -3
  96. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/header.html +8 -3
  97. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/index.html +20 -22
  98. django_whiteneuron-0.4.0.0/whiteneuron/templates/admin/monitoring/dashboard.html +153 -0
  99. django_whiteneuron-0.4.0.0/whiteneuron/templates/admin/monitoring/stat.html +9 -0
  100. django_whiteneuron-0.4.0.0/whiteneuron/templates/admin/monitoring/timeseries.html +11 -0
  101. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/search_form.html +14 -9
  102. django_whiteneuron-0.4.0.0/whiteneuron/templates/admin/signature.html +26 -0
  103. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/base/announcement.html +2 -2
  104. django_whiteneuron-0.4.0.0/whiteneuron/templates/base/forms/mdeditor.html +31 -0
  105. django_whiteneuron-0.4.0.0/whiteneuron/templates/unfold/helpers/account_links.html +67 -0
  106. django_whiteneuron-0.4.0.0/whiteneuron/templates/unfold/helpers/app_list_badge.html +23 -0
  107. django_whiteneuron-0.4.0.0/whiteneuron/templates/unfold/helpers/language_switch.html +17 -0
  108. django_whiteneuron-0.4.0.0/whiteneuron/templates/unfold/helpers/pagination.html +26 -0
  109. django_whiteneuron-0.4.0.0/whiteneuron/templates/unfold/helpers/theme_switch.html +62 -0
  110. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/unfold/helpers/userlinks.html +8 -2
  111. django_whiteneuron-0.4.0.0/whiteneuron/templates/unfold/helpers/wn_page_button.html +7 -0
  112. django_whiteneuron-0.3.1.2/PKG-INFO +0 -351
  113. django_whiteneuron-0.3.1.2/README.md +0 -265
  114. django_whiteneuron-0.3.1.2/django_whiteneuron.egg-info/PKG-INFO +0 -351
  115. django_whiteneuron-0.3.1.2/whiteneuron/base/asgi.py +0 -33
  116. django_whiteneuron-0.3.1.2/whiteneuron/base/filters.py +0 -18
  117. django_whiteneuron-0.3.1.2/whiteneuron/base/middleware.py +0 -430
  118. django_whiteneuron-0.3.1.2/whiteneuron/base/tasks.py +0 -4
  119. django_whiteneuron-0.3.1.2/whiteneuron/base/utils.py +0 -185
  120. django_whiteneuron-0.3.1.2/whiteneuron/base/widgets.py +0 -29
  121. django_whiteneuron-0.3.1.2/whiteneuron/contrib/wn_import_export/tasks.py +0 -40
  122. django_whiteneuron-0.3.1.2/whiteneuron/contrib/wn_modeltranslation/admin.py +0 -48
  123. django_whiteneuron-0.3.1.2/whiteneuron/file_management/utils.py +0 -8
  124. django_whiteneuron-0.3.1.2/whiteneuron/file_management/views.py +0 -50
  125. django_whiteneuron-0.3.1.2/whiteneuron/locale/vi/LC_MESSAGES/django.mo +0 -0
  126. django_whiteneuron-0.3.1.2/whiteneuron/locale/vi/LC_MESSAGES/django.po +0 -1524
  127. django_whiteneuron-0.3.1.2/whiteneuron/notification/consumers.py +0 -18
  128. django_whiteneuron-0.3.1.2/whiteneuron/notification/utils.py +0 -11
  129. django_whiteneuron-0.3.1.2/whiteneuron/notification/views.py +0 -23
  130. django_whiteneuron-0.3.1.2/whiteneuron/static/base/css/btn-styles.css +0 -62
  131. django_whiteneuron-0.3.1.2/whiteneuron/static/base/css/loading.css +0 -18
  132. django_whiteneuron-0.3.1.2/whiteneuron/static/base/css/styles.css +0 -2
  133. django_whiteneuron-0.3.1.2/whiteneuron/static/base/forms/css/html-editor.css +0 -89
  134. django_whiteneuron-0.3.1.2/whiteneuron/static/base/forms/js/format.html.js +0 -171
  135. django_whiteneuron-0.3.1.2/whiteneuron/static/base/forms/js/trix.config.js +0 -257
  136. django_whiteneuron-0.3.1.2/whiteneuron/static/base/js/whiteneuron.js +0 -39
  137. django_whiteneuron-0.3.1.2/whiteneuron/synchronization/admin.py +0 -3
  138. django_whiteneuron-0.3.1.2/whiteneuron/synchronization/apps.py +0 -6
  139. django_whiteneuron-0.3.1.2/whiteneuron/synchronization/models.py +0 -29
  140. django_whiteneuron-0.3.1.2/whiteneuron/synchronization/tests.py +0 -3
  141. django_whiteneuron-0.3.1.2/whiteneuron/synchronization/views.py +0 -3
  142. django_whiteneuron-0.3.1.2/whiteneuron/templates/admin/signature.html +0 -245
  143. django_whiteneuron-0.3.1.2/whiteneuron/templates/unfold/helpers/account_links.html +0 -126
  144. django_whiteneuron-0.3.1.2/whiteneuron/templates/unfold/helpers/app_list_badge.html +0 -53
  145. django_whiteneuron-0.3.1.2/whiteneuron/templates/unfold/helpers/navigation_user.html +0 -41
  146. django_whiteneuron-0.3.1.2/whiteneuron/templates/unfold/helpers/pagination.html +0 -14
  147. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/LICENSE +0 -0
  148. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/django_whiteneuron.egg-info/dependency_links.txt +0 -0
  149. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/django_whiteneuron.egg-info/top_level.txt +0 -0
  150. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/setup.cfg +0 -0
  151. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/__init__.py +0 -0
  152. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/__init__.py +0 -0
  153. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/apps.py +0 -0
  154. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/ckeditor.py +0 -0
  155. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/forms.py +0 -0
  156. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/management/__init__.py +0 -0
  157. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/management/commands/__init__.py +0 -0
  158. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/management/commands/init_groupuser.py +0 -0
  159. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/management/commands/init_guest.py +0 -0
  160. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0001_initial.py +0 -0
  161. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0002_imagemodel_userprofile_user_avatar_user_biography_and_more.py +0 -0
  162. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0003_notification_obj_link.py +0 -0
  163. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0004_delete_notification.py +0 -0
  164. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0005_user_show_softdelete.py +0 -0
  165. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0006_user_is_bot.py +0 -0
  166. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0007_app.py +0 -0
  167. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0008_app_created_at_app_created_by_app_deleted_at_and_more.py +0 -0
  168. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0009_alter_app_table.py +0 -0
  169. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0010_app_category.py +0 -0
  170. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0011_alter_app_options.py +0 -0
  171. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0012_app_permission.py +0 -0
  172. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0013_app_thumbnail_url.py +0 -0
  173. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0014_alter_app_created_at_alter_app_updated_at_and_more.py +0 -0
  174. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0015_ipblacklist.py +0 -0
  175. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0016_uablacklist.py +0 -0
  176. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/0017_alter_uablacklist_pattern.py +0 -0
  177. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/migrations/__init__.py +0 -0
  178. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/resources.py +0 -0
  179. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/sites.py +0 -0
  180. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/templatetags/__init__.py +0 -0
  181. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/templatetags/unfold_list_custom.py +0 -0
  182. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/templatetags/wn_filters.py +0 -0
  183. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/base/thread_local.py +0 -0
  184. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/contrib/__init__.py +0 -0
  185. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/contrib/wn_import_export/__init__.py +0 -0
  186. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/contrib/wn_import_export/constants.py +0 -0
  187. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/contrib/wn_import_export/mixins.py +0 -0
  188. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/contrib/wn_import_export/utils.py +0 -0
  189. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/contrib/wn_modeltranslation/__init__.py +0 -0
  190. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/dashboard/__init__.py +0 -0
  191. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/dashboard/admin.py +0 -0
  192. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/dashboard/apps.py +0 -0
  193. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/dashboard/migrations/__init__.py +0 -0
  194. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/dashboard/models.py +0 -0
  195. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/dashboard/tests.py +0 -0
  196. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/__init__.py +0 -0
  197. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/apps.py +0 -0
  198. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/migrations/0001_initial.py +0 -0
  199. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/migrations/0002_feedbackdata_created_by_feedbackdata_deleted_at_and_more.py +0 -0
  200. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/migrations/0003_feedbackdata_note.py +0 -0
  201. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/migrations/0004_alter_feedbackdata_object_id.py +0 -0
  202. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/migrations/0005_feedbackdata_field.py +0 -0
  203. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/migrations/0006_alter_feedbackdata_created_at_and_more.py +0 -0
  204. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/migrations/__init__.py +0 -0
  205. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/models.py +0 -0
  206. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/tests.py +0 -0
  207. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/utils.py +0 -0
  208. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/feedbacks/views.py +0 -0
  209. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/__init__.py +0 -0
  210. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/apps.py +0 -0
  211. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/migrations/0001_initial.py +0 -0
  212. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/migrations/0002_alter_excelfile_options_alter_pdffile_options_and_more.py +0 -0
  213. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/migrations/0003_alter_excelfile_created_at_and_more.py +0 -0
  214. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/migrations/0004_excelfile_hash_pdffile_hash.py +0 -0
  215. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/migrations/__init__.py +0 -0
  216. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/file_management/tests.py +0 -0
  217. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/manage.py +0 -0
  218. {django_whiteneuron-0.3.1.2/whiteneuron/notification → django_whiteneuron-0.4.0.0/whiteneuron/monitoring}/__init__.py +0 -0
  219. {django_whiteneuron-0.3.1.2/whiteneuron/notification → django_whiteneuron-0.4.0.0/whiteneuron/monitoring}/migrations/__init__.py +0 -0
  220. {django_whiteneuron-0.3.1.2/whiteneuron/synchronization → django_whiteneuron-0.4.0.0/whiteneuron/notification}/__init__.py +0 -0
  221. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/apps.py +0 -0
  222. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/management/commands/call_demo_noti.py +0 -0
  223. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0001_initial.py +0 -0
  224. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0002_alter_notificationconfig_event_type.py +0 -0
  225. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0003_notification.py +0 -0
  226. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0004_alter_notification_flag.py +0 -0
  227. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0005_notification_keywords.py +0 -0
  228. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0006_remove_notification_keywords.py +0 -0
  229. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0007_notification_changed_data.py +0 -0
  230. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0008_alter_notification_changed_data.py +0 -0
  231. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0009_notification_action_by_alter_notification_user.py +0 -0
  232. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0010_alter_notification_user.py +0 -0
  233. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0011_alter_notification_user.py +0 -0
  234. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/migrations/0012_alter_notification_action_and_more.py +0 -0
  235. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/routing.py +0 -0
  236. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/notification/tests.py +0 -0
  237. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/css/ckeditor5.css +0 -0
  238. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/images/delete.svg +0 -0
  239. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/images/edit.svg +0 -0
  240. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/images/icon-viewlink.svg +0 -0
  241. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/images/loading.gif +0 -0
  242. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/images/login-bg.jpg +0 -0
  243. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/images/login_bg.jpg +0 -0
  244. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/images/logo/WhiteNeuron.png +0 -0
  245. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/js/chart.min.js +0 -0
  246. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/static/base/js/d3.v7.min.js +0 -0
  247. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/400.html +0 -0
  248. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/403.html +0 -0
  249. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/404.html +0 -0
  250. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/429.html +0 -0
  251. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/500.html +0 -0
  252. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/auth/user/add_form.html +0 -0
  253. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/base/image_change_form.html +0 -0
  254. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/base/userprofile_change_form.html +0 -0
  255. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/feedbacks/feedback_change_form.html +0 -0
  256. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/login.html +0 -0
  257. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/login_after.html +0 -0
  258. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/submit_line.html +0 -0
  259. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/wn_change_form.html +0 -0
  260. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/admin/wn_history_panel.html +0 -0
  261. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/base/forms/helpers/toolbar.html +0 -0
  262. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/base/forms/wysiwyg.html +0 -0
  263. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/base.html +0 -0
  264. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/file_management/widgets/clearable_file_input_no_download.html +0 -0
  265. {django_whiteneuron-0.3.1.2 → django_whiteneuron-0.4.0.0}/whiteneuron/templates/unfold/helpers/field_password.html +0 -0
@@ -0,0 +1,563 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-whiteneuron
3
+ Version: 0.4.0.0
4
+ Summary: A modern Django Admin extension with enhanced UI/UX, dashboard, feedback, file management, rate limiting, IP blacklisting, and advanced admin integrations built on django-unfold.
5
+ Author-email: White Neuron <anhnt@whiteneuron.ai>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 Nguyễn Tú Anh
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: homepage, https://whiteneuron.ai
29
+ Project-URL: repository, https://github.com/White-Neuron/django-whiteneuron
30
+ Project-URL: changelog, https://github.com/White-Neuron/django-whiteneuron/releases
31
+ Project-URL: Bug Tracker, https://github.com/White-Neuron/django-whiteneuron/issues
32
+ Project-URL: PyPI, https://pypi.org/project/django-whiteneuron/
33
+ Keywords: django,plugin,admin,dashboard,whiteneuron
34
+ Classifier: Development Status :: 4 - Beta
35
+ Classifier: Intended Audience :: Developers
36
+ Classifier: Framework :: Django
37
+ Classifier: Framework :: Django :: 6.0
38
+ Classifier: Programming Language :: Python :: 3
39
+ Classifier: Programming Language :: Python :: 3.13
40
+ Classifier: License :: OSI Approved :: MIT License
41
+ Classifier: Operating System :: OS Independent
42
+ Requires-Python: >=3.13
43
+ Description-Content-Type: text/markdown
44
+ License-File: LICENSE
45
+ Requires-Dist: django-debug-toolbar>=5.0.1
46
+ Requires-Dist: django<7.0.0,>=6.0.8
47
+ Requires-Dist: django-celery-beat>=2.7.0
48
+ Requires-Dist: django-guardian>=2.4.0
49
+ Requires-Dist: django-imagekit>=5.0.0
50
+ Requires-Dist: django-import-export>=4.3.3
51
+ Requires-Dist: django-modeltranslation>=0.19.11
52
+ Requires-Dist: django-ninja>=1.3.0
53
+ Requires-Dist: django-simple-history>=3.8.0
54
+ Requires-Dist: gunicorn>=23.0.0
55
+ Requires-Dist: hiredis>=3.1.0
56
+ Requires-Dist: markdown>=3.7
57
+ Requires-Dist: openai>=1.58.1
58
+ Requires-Dist: openpyxl>=3.1.5
59
+ Requires-Dist: pandas>=2.2.3
60
+ Requires-Dist: pillow>=12.2.0
61
+ Requires-Dist: python-dotenv>=1.0.1
62
+ Requires-Dist: redis>=5.2.1
63
+ Requires-Dist: sentry-sdk==2.28.0
64
+ Requires-Dist: django-browser-reload>=1.18.0
65
+ Requires-Dist: whitenoise>=6.9.0
66
+ Requires-Dist: django-crispy-forms>=2.4
67
+ Requires-Dist: django-colorfield>=0.14.0
68
+ Requires-Dist: channels>=4.2.2
69
+ Requires-Dist: channels-redis>=4.2.1
70
+ Requires-Dist: uvicorn>=0.34.3
71
+ Requires-Dist: daphne>=4.2.0
72
+ Requires-Dist: twisted[tls]>=26.4.0rc2
73
+ Requires-Dist: django-ckeditor-5>=0.2.18
74
+ Requires-Dist: django-cors-headers>=4.3.0
75
+ Requires-Dist: django-unfold<0.111,>=0.109.0
76
+ Requires-Dist: djangoql>=0.18.1
77
+ Requires-Dist: pyopenssl>=26.4.0
78
+ Requires-Dist: md2html-tailwind4==1.5.3
79
+ Requires-Dist: psutil>=7.0.0
80
+ Provides-Extra: dev
81
+ Requires-Dist: pytest; extra == "dev"
82
+ Requires-Dist: black; extra == "dev"
83
+ Requires-Dist: flake8; extra == "dev"
84
+ Requires-Dist: pre-commit; extra == "dev"
85
+ Dynamic: license-file
86
+
87
+ # django-whiteneuron
88
+
89
+ A modern Django Admin extension focused on UI/UX, dashboard, feedback, file management, and advanced admin integrations — built on top of [django-unfold](https://github.com/unfoldadmin/django-unfold).
90
+
91
+ [![PyPI version](https://img.shields.io/pypi/v/django-whiteneuron)](https://pypi.org/project/django-whiteneuron/)
92
+ [![Python](https://img.shields.io/pypi/pyversions/django-whiteneuron)](https://pypi.org/project/django-whiteneuron/)
93
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
94
+ [![Downloads](https://img.shields.io/pypi/dm/django-whiteneuron)](https://pypi.org/project/django-whiteneuron/)
95
+
96
+ ![django-whiteneuron](https://raw.githubusercontent.com/White-Neuron/django-whiteneuron/main2.0/docs/images/main.png)
97
+
98
+ ## Current Version
99
+ v0.4.0.0
100
+
101
+ ## Changelog
102
+
103
+ ### Latest: v0.4.0.0 (2026-10-13)
104
+ **Feature release: daisyUI multi-theme admin, server monitoring dashboard, django-unfold 0.109, security hardening and performance work**
105
+ - **Added**: 35 daisyUI themes selectable from the user menu (**Themes**); each theme also re-colors Unfold and drives its dark mode. `WN_ADMIN_THEMES` limits the picker (`[]` hides it); `WN_THEMES="nord,dracula" bash scripts/tailwind.sh` builds a smaller CSS bundle.
106
+ - **Added**: `whiteneuron.monitoring` — Grafana-style **Server monitoring** dashboard (CPU, memory, disk, load, network, disk I/O, request throughput, p50/p95/p99 latency, error rate, Apdex, slowest endpoints, DB/cache latency) with time ranges, auto-refresh, host selector and shared crosshair. Collect with `manage.py monitoring_collector` or the Celery task `whiteneuron.monitoring.tasks.collect_metrics`; configure with `WN_MONITORING`. New dependency: `psutil`.
107
+ - **Added**: Docker base images `django-whiteneuron-{alpine,debian}:v<version>` built from this repository (`docker/`, moved from WN-Sense); `.github/workflows/docker-base.yml` builds and pushes them on every GitHub Release (secrets `DOCKERHUB_USERNAME` / `DOCKERHUB_TOKEN`).
108
+ - **Changed**: `django-unfold>=0.109.0,<0.111` (the cap is raised after each Unfold release is re-tested against the template overrides); template overrides ported; uses the avatar badge (unread notifications), sidebar sub-navigation (Celery "Schedules"), `SITE_VERSION`, theme-aware dashboard charts.
109
+ - **Security**: escaped notification/grid HTML (stored XSS), whitelisted `?display_fields` (a GET could call `obj.delete()`) and limited the column picker to fields shown on the change form (never `password`; extra exclusions via `ModelAdmin.field_selection_exclude`), staff-only per-user notification WebSocket with origin check, sandboxed uploaded-HTML preview, private exports scoped to the selected rows, `X-Forwarded-For` read from the right (`TRUSTED_PROXY_COUNT`, `IGNORE_X_FORWARDED_FOR`), open-redirect fix in guest login, new-user signal no longer overwrites passwords, `secrets`-based passwords redacted after sending (never passed to the task broker), POST-only feedback resolve, notification IDOR fix.
110
+ - **Security (dependencies)**: locked anyio 4.15.1, urllib3 2.8.0, autobahn 26.7.1, soupsieve 2.10, tablib 3.10.0 (stored XSS in HTML export) and virtualenv 21.14.5 (dev) to patched versions; Tailwind build tooling patched (`npm audit fix`) and the unused `@tailwindcss/typography` removed. `pip-audit` and `npm audit` report no known vulnerabilities.
111
+ - **Performance**: activity logging 1 INSERT per request (was 3–4 queries), dashboard 4 queries (was ~16) + 60s cache, one `bulk_create` + one broadcast per notification, new indexes, atomic rate-limit counters, request-scoped admin state (grid view / page size no longer shared between users), thumbnails built at upload (regenerated if the file is missing), N+1 fixes, 14KB logo instead of 187KB.
112
+ - **Fixed**: dashboard date ranges overlapped by a day, `App.__str__` crash on create, export action signature, `readonly_fields` growing per request, header horizontal overflow on phones, `_(f"…")` strings that could never be translated, Chart.js crash on oklch theme colors, notification WebSocket reconnect loops, monitoring collector stopping when the cache is down, missing site branding (sidebar logo/title) on the monitoring dashboard and admin index, flash messages shown twice on the admin index, changelist toolbar (filter / grid / page-size) hidden for admins without `search_fields`, "Next" enabled on the last page and Previous/Next stuck disabled when Django ignores `?all`, unreadable monitoring colors under several themes, markdown preview styles (md2html_tailwind4 classes were never compiled); Vietnamese translations updated.
113
+ - **Compatibility**: `ModelAdmin.request` still works (now request-scoped, not stored on the shared instance); the *Server monitoring* sidebar link follows the `monitoring.view_metricsample` permission; in the default light/dark modes daisyUI components take their base/primary colors from `UNFOLD["COLORS"]`.
114
+ - **Validation**: 42 package tests pass (`manage.py test whiteneuron`, also under the package's own settings via `whiteneuron.base.testing.package_test_settings`, and from a clean wheel install with django-unfold 0.110.0), `check` clean, `makemigrations` reports no changes, no untranslated Vietnamese strings, Tailwind build and `uv build` succeed; 101 admin URLs swept in a README-style project; changelists, add/change forms, the monitoring dashboard under all 35 themes and the theme picker checked in Chromium (desktop + mobile).
115
+ - **Breaking / behavior changes**:
116
+ - `SECRET_KEY` is required when `DEBUG=False` (build commands such as `collectstatic` are exempt).
117
+ - `WN_ASYNC_TASKS` (Celery for email, export, GPT translation) is opt-in; without it these run inline.
118
+ - Client IP: auto mode uses the right-most public `X-Forwarded-For` hop — set `TRUSTED_PROXY_COUNT`, or `IGNORE_X_FORWARDED_FOR=True` when the app is not behind a proxy.
119
+ - Whole-page cache middleware only with `USE_CACHE_MIDDLEWARE=True`; `EXTENSIONS.modeltranslation` and `compressed_fields` removed (dropped by Unfold); new notifications store plain-text titles and JSON `changed_data`.
120
+ - Project overrides of `unfold/helpers/navigation_user.html` should be compared with Unfold 0.109.
121
+ - **Upgrade Guidance**: `pip install --upgrade django-whiteneuron`, add `"whiteneuron.monitoring"` to `INSTALLED_APPS`, run `migrate` (indexes + monitoring table), `compilemessages`, and start `monitoring_collector` on each host.
122
+ - **Rollback**: revert to v0.3.8.0 after `migrate monitoring zero`, `migrate base 0027` and `migrate notification 0012` (index-only migrations; no data loss).
123
+
124
+ See [CHANGELOG.md](CHANGELOG.md) for the full version history.
125
+
126
+ ### Latest: v0.3.8.0 (2026-09-25)
127
+ **Bugfixes: Django 6 format_html crash in Image previews, app mosaic thumbnail URLs, SHOW_FILE_MANAGEMENT sidebar flag**
128
+ - **Fixed**: `Image.imgThumbnail()` and `Image.imgPreview()` admin methods — replaced f-string interpolation inside `format_html()` with the proper template + args pattern; resolves the rendering crash on Django 6 and ensures interpolated values are HTML-escaped.
129
+ - **Fixed**: App changelist mosaic thumbnails (`templates/admin/base/app_change_list.html`) — relative `thumbnail_url` paths are now wrapped in `{% static %}` while absolute/protocol-relative URLs pass through unchanged, fixing broken thumbnail images.
130
+ - **Fixed**: `SHOW_FILE_MANAGEMENT=False` is no longer silently ignored — the Unfold sidebar is built conditionally at definition time instead of post-processing by title match; when disabled, File Management items merge into the System section before Notifications config.
131
+ - **Compatibility**: No breaking changes; safe for all v0.3.x users. Django 6.0.x only.
132
+
133
+ See [CHANGELOG.md](CHANGELOG.md) for the full version history.
134
+
135
+ ### Latest: v0.3.7.0 (2026-08-23)
136
+ **Security: Patch 6 CVEs across django, cryptography, sqlparse, setuptools**
137
+ - **Fixed**: Upgraded `django` lower bound to patch CVE-2026-15830 (GeoDjango DoS).
138
+ - **Fixed**: Upgraded `pyopenssl` to `>=26.4.0` — patches CVE-2026-69247 (Bleichenbacher oracle attack).
139
+ - **Fixed**: Added `sqlparse >=0.6.0` via transitive deps — patches 3 DoS CVEs (CVE-2026-71491, CVE-2026-54284, CVE-2026-59893).
140
+ - **Fixed**: Added `setuptools >=75.1.0` to build-system — patches CVE-2025-47273.
141
+ - **Compatibility**: No breaking changes; safe for all v0.3.x users. Django 6.0.x only.
142
+
143
+ ### Latest: v0.3.5 (2026-07-15)
144
+ **Feature: Public/private file access control and HTML file support**
145
+ - **Added**: `is_public`, `allowed_users`, `allowed_groups` fields to `BaseFile` model — files can now be marked public or restricted to specific users/groups.
146
+ - **Added**: `_check_access()` permission logic in download/preview views — enforces access control before serving files.
147
+ - **Added**: `HTMLFile` model with inline preview support.
148
+ - **Improved**: Admin UI — public/private badge column, conditional Access Control fieldset for private files.
149
+ - **Compatibility**: No breaking changes; safe for all v0.3.x users.
150
+
151
+ See [CHANGELOG.md](CHANGELOG.md) for the full version history.
152
+
153
+ ### Latest: v0.3.4.12 (2026-06-27)
154
+ **Cleanup: Remove .DS_Store from tracking, feedback list in admin, remove md2html-tailwind4 uv source**
155
+ - **Removed**: 7 `.DS_Store` files removed from git tracking — added `*/.DS_Store` to `.gitignore`.
156
+ - **Added**: `FeedbackBaseAdmin.render_change_form()` loads and passes `feedback_list` context for displaying feedback entries per model instance in admin change form.
157
+ - **Removed**: `[tool.uv.sources]` block for `md2html-tailwind4` from `pyproject.toml`.
158
+ - **Updated**: Tailwind CSS regenerated with v4.1.16.
159
+ - **Compatibility**: No breaking changes; safe for all v0.3.x users.
160
+
161
+ See [CHANGELOG.md](CHANGELOG.md) for the full version history.
162
+
163
+ ### Latest: v0.3.4.10 (2026-06-12)
164
+ **Security patch: Upgrade Django to 6.0.6+ (CVE-2026-8404, CVE-2026-48587, CVE-2026-6873)**
165
+ - **Fixed**: Upgraded `django` lower bound from `>=6.0.6` to `>=6.0.6,<7.0.0` — patches 5 security vulnerabilities: CVE-2026-8404 (CVSS 5.3), CVE-2026-48587 (CVSS 5.3), CVE-2026-6873 (CVSS 4.3), CVE-2026-7666 (CVSS 2.3), CVE-2026-35193 (CVSS 2.3).
166
+ - **Compatibility**: No breaking changes; safe for all v0.3.x users. Django 6.0.x only — pinned upper bound `<7.0.0`.
167
+
168
+ See [CHANGELOG.md](CHANGELOG.md) for the full version history.
169
+
170
+ ### Latest: v0.3.4.8 (2026-05-24)
171
+ **Feature: Badge callback caching layer for dashboard performance optimization**
172
+ - **Added**: Django cache-backed badge callbacks for dashboard model badges with 60s TTL to reduce database queries.
173
+ - **Added**: Per-user cached notification badge with 60s TTL and unauthenticated user guard.
174
+ - **Improved**: Replaced `timezone.now()` with `timezone.localtime()` across all badge queries.
175
+ - **Compatibility**: No breaking changes; safe for all v0.3.x users. Requires Django cache backend configured.
176
+
177
+ See [CHANGELOG.md](CHANGELOG.md) for the full version history.
178
+
179
+ ### Latest: v0.3.4.6.2 (2026-05-14)
180
+ **Improvement: Configurable rate-limit exempt paths and user activity exclude paths**
181
+ - **Improved**: `RateLimitMiddleware` now reads `RATE_LIMIT_EXEMPT_PATHS` from Django settings — comma-separated list of additional path prefixes to exclude from rate limiting.
182
+ - **Improved**: `UserActivityMiddleware` now reads `USER_ACTIVITY_EXCLUDE_PATHS` from Django settings — semicolon-separated list of `path,condition` pairs for excluding paths from activity tracking and rate limiting.
183
+ - **Compatibility**: No breaking changes; safe for all v0.3.x users. New settings are optional.
184
+
185
+ See [CHANGELOG.md](CHANGELOG.md) for the full version history.
186
+
187
+ ### Latest: v0.3.3.4 (2026-04-30)
188
+ **Patch release: Remove synchronization module, add language switcher template, update Vietnamese i18n**
189
+ - **Removed**: `synchronization/` module — cleaned up unused sync models, admin, views, tests, and migrations
190
+ - **Added**: Language switcher template for Unfold admin (`language_switch.html`) with multi-language support via `show_languages` context variable
191
+ - **Improved**: Vietnamese translations updated — removed stale synchronization references, added new entries for user profile and HTML editor
192
+ - **Compatibility**: No breaking changes; safe for all v0.3.3.x users
193
+ - **Validation**: Build, migrations (no changes), and manual admin UI/UX validation performed
194
+ - **Upgrade Guidance**: No manual migration required; upgrade recommended for all users on v0.3.3.x
195
+ - **Rollback**: Safe to revert to v0.3.3.3; no schema changes introduced
196
+
197
+ See [CHANGELOG.md](CHANGELOG.md) for the full version history.
198
+
199
+ ## Table of Contents
200
+
201
+ - [Changelog](#changelog)
202
+ - [Features](#features)
203
+ - [Installation](#installation)
204
+ - [Quick Start](#quick-start)
205
+ - [Configuration](#configuration)
206
+ - [Modules](#modules)
207
+ - [Middleware & Security](#middleware--security)
208
+ - [Frontend](#frontend)
209
+ - [Environment Variables](#environment-variables)
210
+ - [Management Commands](#management-commands)
211
+ - [Building & Releasing](#building--releasing)
212
+ - [Documentation](#documentation)
213
+ - [Contact](#contact)
214
+
215
+ ## Giới thiệu
216
+
217
+ Xem [docs/INTRODUCTION.md](docs/INTRODUCTION.md) để tìm hiểu chi tiết về django-whiteneuron — tại sao nên dùng, tính năng nổi bật và ai phù hợp.
218
+
219
+ ## Features
220
+
221
+ | Category | Feature | Description |
222
+ |---|---|---|
223
+ | **Core** | Custom User Model | UUID-based user model with bot support, avatar, biography |
224
+ | **Core** | Soft Delete System | `BaseModel` with soft delete, restore, and audit trail (`created_by`, `updated_by`) |
225
+ | **Core** | Auto Notifications | Real-time WebSocket notifications on CRUD operations via `BaseModel.save()` |
226
+ | **Dashboard** | Admin Dashboard | Custom dashboard callback with badge system, cache-backed for performance |
227
+ | **Security** | Rate Limiting | IP-based and user-based rate limiting with Redis backend (429 responses) |
228
+ | **Security** | IP Blacklist | Static (`.env` CIDR) + dynamic (admin-managed, Redis TTL) blocking |
229
+ | **Security** | UA Blacklist | User-Agent substring/regex matching via admin panel or `.env` |
230
+ | **Tracking** | Activity Logs | `UserActivity`, `AnonymousActivity`, `VisitProfile` — full request audit trail |
231
+ | **Files** | File Management | Excel/PDF upload with SHA-256 integrity verification |
232
+ | **Feedback** | Feedback System | Per-model feedback collection, viewable in admin change forms |
233
+ | **Admin** | Grid View | Card-based user listing with avatar, badges, and role indicators |
234
+ | **Admin** | Import/Export | `django-import-export` integration for data portability |
235
+ | **Admin** | Simple History | `django-simple-history` tracking on all models |
236
+ | **Admin** | Guardian Integration | Object-level permissions via `django-guardian` |
237
+ | **Editor** | CKEditor 5 | Rich text editing with Tailwind-styled output |
238
+ | **Email** | Login Notifications | Auto-generate password + send login email on user creation |
239
+
240
+ ## Installation
241
+
242
+ ### From PyPI (recommended)
243
+
244
+ ```bash
245
+ pip install django-whiteneuron
246
+ ```
247
+
248
+ Or with [uv](https://github.com/astral-sh/uv):
249
+
250
+ ```bash
251
+ uv add django-whiteneuron
252
+ ```
253
+
254
+ ### Specific version from PyPI
255
+
256
+ ```bash
257
+ uv add "django-whiteneuron==0.3.4.12"
258
+ ```
259
+
260
+ ### From GitHub tag
261
+
262
+ ```bash
263
+ uv add "git+https://github.com/White-Neuron/django-whiteneuron.git@v0.3.4.12"
264
+ ```
265
+
266
+ ### From local source
267
+
268
+ ```bash
269
+ uv pip install -e .
270
+ ```
271
+
272
+ ## Quick Start
273
+
274
+ ```bash
275
+ # 1. Add to INSTALLED_APPS (top of list)
276
+ # settings.py
277
+ INSTALLED_APPS = [
278
+ "whiteneuron",
279
+ "whiteneuron.base",
280
+ "whiteneuron.feedbacks",
281
+ "whiteneuron.file_management",
282
+ "whiteneuron.contrib",
283
+ "whiteneuron.dashboard",
284
+ # ... your other apps
285
+ ]
286
+
287
+ # 2. Set custom user model
288
+ AUTH_USER_MODEL = "base.User"
289
+
290
+ # 3. Add middleware (order matters)
291
+ MIDDLEWARE = [
292
+ "django.middleware.security.SecurityMiddleware",
293
+ "whiteneuron.base.middleware.RateLimitMiddleware", # ← immediately after SecurityMiddleware
294
+ "whitenoise.middleware.WhiteNoiseMiddleware",
295
+ "django.contrib.sessions.middleware.SessionMiddleware",
296
+ "django.middleware.common.CommonMiddleware",
297
+ "django.middleware.csrf.CsrfViewMiddleware",
298
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
299
+ "django.contrib.messages.middleware.MessageMiddleware",
300
+ "django.middleware.clickjacking.XFrameOptionsMiddleware",
301
+ "whiteneuron.base.middleware.ReadonlyExceptionHandlerMiddleware",
302
+ "whiteneuron.base.middleware.UserActivityMiddleware", # ← after AuthenticationMiddleware
303
+ "whiteneuron.base.middleware.ThreadLocalMiddleware",
304
+ ]
305
+
306
+ # 4. Run migrations
307
+ python manage.py migrate
308
+
309
+ # 5. Create superuser and start
310
+ python manage.py createsuperuser
311
+ python manage.py runserver
312
+ ```
313
+
314
+ Access the admin at: `http://127.0.0.1:8000/admin/`
315
+
316
+ ## Configuration
317
+
318
+ ### UNFOLD Settings Example
319
+
320
+ ```python
321
+ from django.templatetags.static import static
322
+ from django.utils.translation import gettext_lazy as _
323
+
324
+ UNFOLD = {
325
+ "SITE_HEADER": _("White Neuron"),
326
+ "SITE_TITLE": _("White Neuron Admin"),
327
+ "SITE_SUBHEADER": _("Admin panel"),
328
+ "SITE_ICON": {
329
+ "light": lambda request: static("base/images/logo/WhiteNeuron-128.png"),
330
+ "dark": lambda request: static("base/images/logo/WhiteNeuron-128.png"),
331
+ },
332
+ "SITE_FAVICONS": [
333
+ {
334
+ "rel": "icon",
335
+ "sizes": "32x32",
336
+ "type": "image/png",
337
+ "href": lambda request: static("base/images/logo/WhiteNeuron-32.png"),
338
+ },
339
+ ],
340
+ "SHOW_HISTORY": False,
341
+ "SHOW_LANGUAGES": True,
342
+ "SHOW_VIEW_ON_SITE": True,
343
+ "SHOW_BACK_BUTTON": True,
344
+ "DASHBOARD_CALLBACK": "whiteneuron.dashboard.views.dashboard_callback",
345
+ "LOGIN": {
346
+ "image": lambda request: static("base/images/login-bg.jpg"),
347
+ },
348
+ "STYLES": [
349
+ lambda request: static("base/css/styles.css"),
350
+ lambda request: static("base/css/btn-styles.css"),
351
+ lambda request: static("base/css/loading.css"),
352
+ ],
353
+ "SCRIPTS": [
354
+ lambda request: static("base/js/loading.js"),
355
+ lambda request: static("base/js/whiteneuron.js"),
356
+ ],
357
+ "BORDER_RADIUS": "6px",
358
+ }
359
+ ```
360
+
361
+ ### Server monitoring dashboard
362
+
363
+ `whiteneuron.monitoring` adds a Grafana-style dashboard at **System → Server monitoring**
364
+ (superusers, or staff with the `view_metricsample` permission):
365
+
366
+ - **Overview**: uptime, CPU, memory, disk, load, throughput, 5xx error rate and p95 latency,
367
+ with sparklines and green / orange / red thresholds.
368
+ - **System**: CPU / memory / disk gauges, per-core heatmap, CPU, load, memory, disk I/O,
369
+ network and disk space time series.
370
+ - **Application** (from the request logs `UserActivityMiddleware` already writes): requests
371
+ per minute by outcome, p50 / p95 / p99 latency, status-code breakdown, Apdex score, and the
372
+ slowest endpoints (IDs are grouped, e.g. `/user/:id/change/`).
373
+ - **Process & dependencies**: database and cache round-trip time, app memory and threads.
374
+ - Time range 5m–7d, auto-refresh (off–5m), host selector, shared crosshair across charts,
375
+ shareable URLs (`?range=6h&refresh=30s&host=web-1`), follows the selected admin theme.
376
+
377
+ Add `"whiteneuron.monitoring"` to `INSTALLED_APPS`, run `migrate`, then collect samples on
378
+ each host (the dashboard also stores a sample while it is open, at most once per interval):
379
+
380
+ ```bash
381
+ python manage.py monitoring_collector # long-running, e.g. a systemd service
382
+ python manage.py monitoring_collector --once # single sample (cron)
383
+ ```
384
+
385
+ or schedule the Celery task `whiteneuron.monitoring.tasks.collect_metrics` with celery beat.
386
+
387
+ ```python
388
+ WN_MONITORING = {
389
+ "INTERVAL": 15, # seconds between samples
390
+ "RETENTION_DAYS": 7, # older samples are pruned automatically
391
+ "DISK_PATH": "/", # filesystem shown in the disk panels
392
+ # "HOST": "web-1", # defaults to the machine hostname
393
+ }
394
+ ```
395
+
396
+ ### Admin themes (daisyUI)
397
+
398
+ All 35 daisyUI themes are compiled into `base/css/styles.css` and selectable from the user menu (**Themes**). The selected theme also re-colors Unfold (primary/base palettes), and its light/dark scheme drives Unfold's dark mode. The choice is stored per browser.
399
+
400
+ ```python
401
+ # Optional: limit the themes offered in the picker (Light/Dark/System are always available)
402
+ WN_ADMIN_THEMES = ["corporate", "nord", "dracula", "forest"] # [] hides the picker
403
+ ```
404
+
405
+ To ship a smaller CSS bundle, compile only some themes: `WN_THEMES="nord,dracula" bash scripts/tailwind.sh`.
406
+
407
+ ## Modules
408
+
409
+ | Module | Description | Key Models |
410
+ |---|---|---|
411
+ | `whiteneuron.base` | Core models, admin, middleware, utilities | `User`, `BaseModel`, `Image`, `Mail`, `App`, `IPBlacklist`, `UABlacklist` |
412
+ | `whiteneuron.dashboard` | Dashboard callback and badge system | — |
413
+ | `whiteneuron.notification` | WebSocket real-time notifications | `Notification`, `NotificationConfig` |
414
+ | `whiteneuron.file_management` | File upload with integrity verification | `ExcelFile`, `PDFFile` |
415
+ | `whiteneuron.feedbacks` | Per-model feedback collection | — |
416
+
417
+ ## Middleware & Security
418
+
419
+ ### Rate Limiting
420
+
421
+ ```python
422
+ RATE_LIMIT_REQUESTS = 60 # max requests per window (by IP)
423
+ RATE_LIMIT_WINDOW = 60 # in seconds
424
+ USER_RATE_LIMIT_REQUESTS = 60 # by authenticated user
425
+ USER_RATE_LIMIT_WINDOW = 60
426
+ ```
427
+
428
+ When limit exceeded:
429
+ - API (`/api/` or `Accept: application/json`) → JSON `{"detail": "Too many requests."}` (429)
430
+ - Browser → renders `429.html` with `Retry-After` header
431
+
432
+ ### IP Blacklist
433
+
434
+ **Static** — `.env` (CIDR ranges, loaded at startup):
435
+ ```env
436
+ IP_BLACKLIST=185.220.101.5,194.165.16.0/22,2001:db8::/32
437
+ ```
438
+
439
+ **Dynamic** — Admin panel + Redis (real-time):
440
+ - Permanent block: leave `blocked_until` empty
441
+ - Temporary block: set `blocked_until` → Redis TTL auto-expires
442
+
443
+ ### UA Blacklist
444
+
445
+ Static via `.env`:
446
+ ```env
447
+ UA_BLACKLIST=GPTBot,ClaudeBot,https://openai.com
448
+ ```
449
+
450
+ Dynamic via admin — supports regex patterns with real-time cache rebuild.
451
+
452
+ ## Frontend (Tailwind 4 + daisyUI 5)
453
+
454
+ ```bash
455
+ npm install -D @tailwindcss/cli@next daisyui@latest
456
+ bash scripts/tailwind.sh
457
+ ```
458
+
459
+ Or directly:
460
+ ```bash
461
+ npx @tailwindcss/cli -i styles.css -o whiteneuron/static/base/css/styles.css --minify
462
+ ```
463
+
464
+ ## Environment Variables
465
+
466
+ Copy `env.example` to `.env` and configure. Key variables:
467
+
468
+ | Variable | Description | Default |
469
+ |---|---|---|
470
+ | `SECRET_KEY` | Django secret key | — |
471
+ | `DEBUG` | Debug mode | `True` |
472
+ | `DATABASE` | Database type (`sqlite`/`postgres`) | `sqlite` |
473
+ | `REDIS` / `CACHE_REDIS_LOCATION` | Redis connection | `redis://127.0.0.1:6379` |
474
+ | `CELERY_BROKER_URL` | Celery broker URL | `redis://localhost:6379/0` |
475
+ | `RATE_LIMIT_REQUESTS` | IP rate limit count | `60` |
476
+ | `IP_BLACKLIST` | Static IP blocks (CIDR) | — |
477
+ | `UA_BLACKLIST` | Static UA blocks | — |
478
+
479
+ See `env.example` for the full list.
480
+
481
+ ## Management Commands
482
+
483
+ | Command | Description |
484
+ |---|---|
485
+ | `init_admin` | Create initial admin user |
486
+ | `init_guest` | Create guest user account |
487
+ | `init_groupuser` | Initialize group users |
488
+ | `cleanup_old_activities` | Remove old activity records |
489
+ | `update_visit_profiles` | Update visit profile data |
490
+
491
+ ## Building & Releasing
492
+
493
+ ```bash
494
+ bash scripts/build.sh
495
+ ```
496
+
497
+ This builds Tailwind CSS assets, runs migrations, and creates the Python package via `uv build`.
498
+
499
+ Publishing a **GitHub Release** (tag `v<version>`, equal to `version` in `pyproject.toml`) runs two
500
+ workflows: `python-publish.yml` uploads the package to PyPI, and `docker-base.yml` builds and pushes
501
+ the Docker base images.
502
+
503
+ ### Docker base images
504
+
505
+ `anhneuron/django-whiteneuron-alpine:v<version>` and `anhneuron/django-whiteneuron-debian:v<version>`
506
+ contain Python 3.13 with this package installed. Its dependencies are pinned from `uv.lock`, the
507
+ same set CI tests. The images run as `appuser` (uid 100, gid 101, home `/app`). Projects build
508
+ `FROM` them, for example WN-Sense's web (Alpine) and core (Debian) images.
509
+
510
+ Every build goes through `docker/build-base.sh`:
511
+ - The source is a `git archive` of the chosen ref, never local files.
512
+ - Dependencies come from that ref's `uv.lock` (`uv export`).
513
+ - The Dockerfiles come from the current checkout, so older tags can be built too.
514
+ - Pushing is only allowed for the release tag `v<version>`, which must match `pyproject.toml`.
515
+ A published tag is never rebuilt from other code.
516
+ - Each image fails to build if the installed version differs from its tag.
517
+
518
+ **CI/CD**: `.github/workflows/docker-base.yml` builds and pushes both images when a GitHub
519
+ Release is published.
520
+ - Required repository secrets: `DOCKERHUB_USERNAME` and `DOCKERHUB_TOKEN` (a Docker Hub access
521
+ token with write access).
522
+ - Optional repository variable: `DOCKERHUB_NAMESPACE` (default `anhneuron`).
523
+ - *Actions → Docker base images → Run workflow* builds any ref. Pushing from there also needs a
524
+ release tag.
525
+ - Pull requests that touch `docker/`, `pyproject.toml` or `uv.lock` only build the images.
526
+
527
+ **By hand** (needs git, uv and docker buildx):
528
+
529
+ ```bash
530
+ bash docker/build-base.sh # HEAD, load into local docker
531
+ GIT_REF=v0.3.8.0 bash docker/build-base.sh # a tag / branch / commit
532
+ GIT_REF=v0.4.0.0 bash docker/push-base.sh # push a release, with provenance and SBOM
533
+ VARIANTS=alpine IMAGE_NAMESPACE=myorg WN_PYTHON_VERSION=3.13 bash docker/build-base.sh
534
+ ```
535
+
536
+ ## Error Pages
537
+
538
+ Templates in `whiteneuron/templates/` are used automatically when `DEBUG=False`:
539
+
540
+ | Template | Error |
541
+ |---|---|
542
+ | `400.html` | Bad Request |
543
+ | `403.html` | Forbidden |
544
+ | `404.html` | Not Found |
545
+ | `429.html` | Too Many Requests |
546
+ | `500.html` | Server Error |
547
+
548
+ ## Documentation
549
+
550
+ - **Giới thiệu**: Xem [docs/INTRODUCTION.md](docs/INTRODUCTION.md) — tài liệu giới thiệu dự án, tính năng nổi bật và ai nên dùng.
551
+ - **Hướng dẫn chi tiết**: Xem [docs/GUIDE.md](docs/GUIDE.md) cho tài liệu module, model, middleware và cấu hình đầy đủ.
552
+ - **Changelog**: See [CHANGELOG.md](CHANGELOG.md) for full version history.
553
+ - **CKEditor 5 Customization**: See [docs/CKEDITOR5_CUSTOMIZATION.md](docs/CKEDITOR5_CUSTOMIZATION.md).
554
+
555
+ ## Contact
556
+
557
+ - Email: [anhnt@whiteneuron.com](mailto:anhnt@whiteneuron.com)
558
+ - Website: [https://whiteneuron.ai](https://whiteneuron.ai)
559
+ - GitHub: [https://github.com/White-Neuron/django-whiteneuron](https://github.com/White-Neuron/django-whiteneuron)
560
+
561
+ ## License
562
+
563
+ MIT License.