django-whiteneuron 0.3.0.3__tar.gz → 0.3.1.2__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 (194) hide show
  1. django_whiteneuron-0.3.1.2/PKG-INFO +351 -0
  2. django_whiteneuron-0.3.1.2/README.md +265 -0
  3. django_whiteneuron-0.3.1.2/django_whiteneuron.egg-info/PKG-INFO +351 -0
  4. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/django_whiteneuron.egg-info/SOURCES.txt +3 -1
  5. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/django_whiteneuron.egg-info/requires.txt +2 -1
  6. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/pyproject.toml +3 -2
  7. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/modeladmin.py +2 -0
  8. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/settings.py +13 -2
  9. django_whiteneuron-0.3.1.2/whiteneuron/base/sites.py +35 -0
  10. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/urls.py +2 -2
  11. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/utils.py +21 -1
  12. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/views.py +10 -1
  13. django_whiteneuron-0.3.1.2/whiteneuron/locale/vi/LC_MESSAGES/django.mo +0 -0
  14. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/locale/vi/LC_MESSAGES/django.po +184 -150
  15. django_whiteneuron-0.3.1.2/whiteneuron/static/base/css/styles.css +2 -0
  16. django_whiteneuron-0.3.1.2/whiteneuron/templates/base/announcement.html +75 -0
  17. django_whiteneuron-0.3.1.2/whiteneuron/templates/unfold/helpers/userlinks.html +46 -0
  18. django_whiteneuron-0.3.0.3/PKG-INFO +0 -576
  19. django_whiteneuron-0.3.0.3/README.md +0 -491
  20. django_whiteneuron-0.3.0.3/django_whiteneuron.egg-info/PKG-INFO +0 -576
  21. django_whiteneuron-0.3.0.3/whiteneuron/base/sites.py +0 -13
  22. django_whiteneuron-0.3.0.3/whiteneuron/locale/vi/LC_MESSAGES/django.mo +0 -0
  23. django_whiteneuron-0.3.0.3/whiteneuron/static/base/css/styles.css +0 -2
  24. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/LICENSE +0 -0
  25. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/django_whiteneuron.egg-info/dependency_links.txt +0 -0
  26. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/django_whiteneuron.egg-info/top_level.txt +0 -0
  27. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/setup.cfg +0 -0
  28. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/__init__.py +0 -0
  29. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/__init__.py +0 -0
  30. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/admin.py +0 -0
  31. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/apps.py +0 -0
  32. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/asgi.py +0 -0
  33. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/ckeditor.py +0 -0
  34. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/filters.py +0 -0
  35. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/forms.py +0 -0
  36. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/management/__init__.py +0 -0
  37. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/management/commands/__init__.py +0 -0
  38. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/management/commands/init_admin.py +0 -0
  39. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/management/commands/init_groupuser.py +0 -0
  40. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/management/commands/init_guest.py +0 -0
  41. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/middleware.py +0 -0
  42. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/migrations/0001_initial.py +0 -0
  43. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/migrations/0002_imagemodel_userprofile_user_avatar_user_biography_and_more.py +0 -0
  44. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/migrations/0003_notification_obj_link.py +0 -0
  45. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/migrations/0004_delete_notification.py +0 -0
  46. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/migrations/0005_user_show_softdelete.py +0 -0
  47. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/migrations/0006_user_is_bot.py +0 -0
  48. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/migrations/0007_app.py +0 -0
  49. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/migrations/0008_app_created_at_app_created_by_app_deleted_at_and_more.py +0 -0
  50. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/migrations/0009_alter_app_table.py +0 -0
  51. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/migrations/0010_app_category.py +0 -0
  52. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/migrations/0011_alter_app_options.py +0 -0
  53. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/migrations/0012_app_permission.py +0 -0
  54. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/migrations/0013_app_thumbnail_url.py +0 -0
  55. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/migrations/0014_alter_app_created_at_alter_app_updated_at_and_more.py +0 -0
  56. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/migrations/0015_ipblacklist.py +0 -0
  57. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/migrations/0016_uablacklist.py +0 -0
  58. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/migrations/0017_alter_uablacklist_pattern.py +0 -0
  59. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/migrations/__init__.py +0 -0
  60. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/models.py +0 -0
  61. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/resources.py +0 -0
  62. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/tasks.py +0 -0
  63. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/templatetags/__init__.py +0 -0
  64. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/templatetags/unfold_list_custom.py +0 -0
  65. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/templatetags/wn_filters.py +0 -0
  66. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/tests.py +0 -0
  67. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/thread_local.py +0 -0
  68. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/base/widgets.py +0 -0
  69. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/contrib/__init__.py +0 -0
  70. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/contrib/wn_import_export/__init__.py +0 -0
  71. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/contrib/wn_import_export/admin.py +0 -0
  72. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/contrib/wn_import_export/constants.py +0 -0
  73. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/contrib/wn_import_export/mixins.py +0 -0
  74. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/contrib/wn_import_export/tasks.py +0 -0
  75. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/contrib/wn_import_export/utils.py +0 -0
  76. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/contrib/wn_modeltranslation/__init__.py +0 -0
  77. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/contrib/wn_modeltranslation/admin.py +0 -0
  78. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/contrib/wn_modeltranslation/utils.py +0 -0
  79. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/dashboard/__init__.py +0 -0
  80. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/dashboard/admin.py +0 -0
  81. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/dashboard/apps.py +0 -0
  82. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/dashboard/migrations/__init__.py +0 -0
  83. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/dashboard/models.py +0 -0
  84. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/dashboard/tests.py +0 -0
  85. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/dashboard/views.py +0 -0
  86. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/feedbacks/__init__.py +0 -0
  87. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/feedbacks/admin.py +0 -0
  88. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/feedbacks/apps.py +0 -0
  89. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/feedbacks/migrations/0001_initial.py +0 -0
  90. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/feedbacks/migrations/0002_feedbackdata_created_by_feedbackdata_deleted_at_and_more.py +0 -0
  91. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/feedbacks/migrations/0003_feedbackdata_note.py +0 -0
  92. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/feedbacks/migrations/0004_alter_feedbackdata_object_id.py +0 -0
  93. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/feedbacks/migrations/0005_feedbackdata_field.py +0 -0
  94. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/feedbacks/migrations/0006_alter_feedbackdata_created_at_and_more.py +0 -0
  95. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/feedbacks/migrations/__init__.py +0 -0
  96. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/feedbacks/models.py +0 -0
  97. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/feedbacks/tests.py +0 -0
  98. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/feedbacks/urls.py +0 -0
  99. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/feedbacks/utils.py +0 -0
  100. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/feedbacks/views.py +0 -0
  101. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/file_management/__init__.py +0 -0
  102. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/file_management/admin.py +0 -0
  103. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/file_management/apps.py +0 -0
  104. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/file_management/migrations/0001_initial.py +0 -0
  105. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/file_management/migrations/0002_alter_excelfile_options_alter_pdffile_options_and_more.py +0 -0
  106. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/file_management/migrations/0003_alter_excelfile_created_at_and_more.py +0 -0
  107. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/file_management/migrations/0004_excelfile_hash_pdffile_hash.py +0 -0
  108. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/file_management/migrations/__init__.py +0 -0
  109. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/file_management/models.py +0 -0
  110. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/file_management/tests.py +0 -0
  111. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/file_management/urls.py +0 -0
  112. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/file_management/utils.py +0 -0
  113. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/file_management/views.py +0 -0
  114. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/manage.py +0 -0
  115. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/__init__.py +0 -0
  116. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/admin.py +0 -0
  117. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/apps.py +0 -0
  118. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/consumers.py +0 -0
  119. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/management/__init__.py +0 -0
  120. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/management/commands/__init__.py +0 -0
  121. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/management/commands/call_demo_noti.py +0 -0
  122. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/migrations/0001_initial.py +0 -0
  123. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/migrations/0002_alter_notificationconfig_event_type.py +0 -0
  124. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/migrations/0003_notification.py +0 -0
  125. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/migrations/0004_alter_notification_flag.py +0 -0
  126. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/migrations/0005_notification_keywords.py +0 -0
  127. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/migrations/0006_remove_notification_keywords.py +0 -0
  128. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/migrations/0007_notification_changed_data.py +0 -0
  129. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/migrations/0008_alter_notification_changed_data.py +0 -0
  130. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/migrations/0009_notification_action_by_alter_notification_user.py +0 -0
  131. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/migrations/0010_alter_notification_user.py +0 -0
  132. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/migrations/0011_alter_notification_user.py +0 -0
  133. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/migrations/0012_alter_notification_action_and_more.py +0 -0
  134. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/migrations/__init__.py +0 -0
  135. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/models.py +0 -0
  136. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/routing.py +0 -0
  137. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/tests.py +0 -0
  138. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/utils.py +0 -0
  139. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/notification/views.py +0 -0
  140. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/static/base/css/btn-styles.css +0 -0
  141. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/static/base/css/ckeditor5.css +0 -0
  142. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/static/base/css/loading.css +0 -0
  143. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/static/base/forms/css/html-editor.css +0 -0
  144. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/static/base/forms/js/format.html.js +0 -0
  145. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/static/base/forms/js/trix.config.js +0 -0
  146. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/static/base/images/delete.svg +0 -0
  147. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/static/base/images/edit.svg +0 -0
  148. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/static/base/images/icon-viewlink.svg +0 -0
  149. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/static/base/images/loading.gif +0 -0
  150. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/static/base/images/login-bg.jpg +0 -0
  151. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/static/base/images/login_bg.jpg +0 -0
  152. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/static/base/images/logo/WhiteNeuron.png +0 -0
  153. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/static/base/js/chart.min.js +0 -0
  154. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/static/base/js/d3.v7.min.js +0 -0
  155. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/static/base/js/loading.js +0 -0
  156. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/static/base/js/whiteneuron.js +0 -0
  157. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/synchronization/__init__.py +0 -0
  158. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/synchronization/admin.py +0 -0
  159. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/synchronization/apps.py +0 -0
  160. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/synchronization/migrations/__init__.py +0 -0
  161. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/synchronization/models.py +0 -0
  162. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/synchronization/tests.py +0 -0
  163. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/synchronization/views.py +0 -0
  164. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/400.html +0 -0
  165. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/403.html +0 -0
  166. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/404.html +0 -0
  167. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/429.html +0 -0
  168. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/500.html +0 -0
  169. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/admin/auth/user/add_form.html +0 -0
  170. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/admin/base/app_change_list.html +0 -0
  171. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/admin/base/image_change_form.html +0 -0
  172. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/admin/base/userprofile_change_form.html +0 -0
  173. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/admin/base.html +0 -0
  174. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/admin/change_list.html +0 -0
  175. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/admin/feedbacks/feedback_change_form.html +0 -0
  176. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/admin/grid_view_results.html +0 -0
  177. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/admin/header.html +0 -0
  178. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/admin/index.html +0 -0
  179. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/admin/login.html +0 -0
  180. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/admin/login_after.html +0 -0
  181. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/admin/search_form.html +0 -0
  182. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/admin/signature.html +0 -0
  183. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/admin/submit_line.html +0 -0
  184. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/admin/wn_change_form.html +0 -0
  185. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/admin/wn_history_panel.html +0 -0
  186. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/base/forms/helpers/toolbar.html +0 -0
  187. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/base/forms/wysiwyg.html +0 -0
  188. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/base.html +0 -0
  189. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/file_management/widgets/clearable_file_input_no_download.html +0 -0
  190. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/unfold/helpers/account_links.html +0 -0
  191. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/unfold/helpers/app_list_badge.html +0 -0
  192. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/unfold/helpers/field_password.html +0 -0
  193. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/unfold/helpers/navigation_user.html +0 -0
  194. {django_whiteneuron-0.3.0.3 → django_whiteneuron-0.3.1.2}/whiteneuron/templates/unfold/helpers/pagination.html +0 -0
@@ -0,0 +1,351 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-whiteneuron
3
+ Version: 0.3.1.2
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 :: 5.2
38
+ Classifier: Programming Language :: Python :: 3
39
+ Classifier: Programming Language :: Python :: 3.11
40
+ Classifier: Programming Language :: Python :: 3.12
41
+ Classifier: License :: OSI Approved :: MIT License
42
+ Classifier: Operating System :: OS Independent
43
+ Requires-Python: >=3.11
44
+ Description-Content-Type: text/markdown
45
+ License-File: LICENSE
46
+ Requires-Dist: django-debug-toolbar>=5.0.1
47
+ Requires-Dist: django>=5.2.13
48
+ Requires-Dist: django-celery-beat>=2.7.0
49
+ Requires-Dist: django-guardian>=2.4.0
50
+ Requires-Dist: django-imagekit>=5.0.0
51
+ Requires-Dist: django-import-export>=4.3.3
52
+ Requires-Dist: django-modeltranslation>=0.19.11
53
+ Requires-Dist: django-ninja>=1.3.0
54
+ Requires-Dist: django-simple-history>=3.8.0
55
+ Requires-Dist: gunicorn>=23.0.0
56
+ Requires-Dist: hiredis>=3.1.0
57
+ Requires-Dist: markdown>=3.7
58
+ Requires-Dist: openai>=1.58.1
59
+ Requires-Dist: openpyxl>=3.1.5
60
+ Requires-Dist: pandas>=2.2.3
61
+ Requires-Dist: pillow>=12.2.0
62
+ Requires-Dist: python-dotenv>=1.0.1
63
+ Requires-Dist: redis>=5.2.1
64
+ Requires-Dist: sentry-sdk==2.28.0
65
+ Requires-Dist: django-browser-reload>=1.18.0
66
+ Requires-Dist: whitenoise>=6.9.0
67
+ Requires-Dist: django-crispy-forms>=2.4
68
+ Requires-Dist: django-colorfield>=0.14.0
69
+ Requires-Dist: channels>=4.2.2
70
+ Requires-Dist: channels-redis>=4.2.1
71
+ Requires-Dist: uvicorn>=0.34.3
72
+ Requires-Dist: daphne>=4.2.0
73
+ Requires-Dist: django-ckeditor-5>=0.2.18
74
+ Requires-Dist: django-cors-headers>=4.3.0
75
+ Requires-Dist: django-unfold>=0.89.0
76
+ Requires-Dist: djangoql>=0.18.1
77
+ Requires-Dist: cryptography>=46.0.7
78
+ Requires-Dist: pyopenssl==26.0.0
79
+ Requires-Dist: md2html-tailwind4>=1.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
+
100
+ - 0.3.1.2
101
+
102
+ ## Compatibility
103
+
104
+ - Python >= 3.11
105
+ - Django >= 5.2.13
106
+ - django-unfold >= 0.89.0
107
+ - Tailwind CSS 4.x + daisyUI 5.x (for the bundled frontend styles)
108
+
109
+ ## Changelog
110
+
111
+ See [CHANGELOG.md](CHANGELOG.md) for the full version history.
112
+
113
+ ### Latest: v0.3.1.2 (2026-04-16)
114
+ **Dependency: Bump django-unfold floor constraint to >=0.89.0**
115
+ - **Updated**: `pyproject.toml` — raised `django-unfold` minimum version from `>=0.85.0` to `>=0.89.0`; incorporates improvements from 0.86.0–0.89.0 (compressed fields by default, removal of unbound template blocks, inline before/after templates).
116
+ - **Updated**: `uv.lock` — lock file refreshed to reflect the updated constraint.
117
+
118
+ ## Installation
119
+
120
+ ### From PyPI (recommended)
121
+
122
+ ```bash
123
+ pip install django-whiteneuron
124
+ ```
125
+
126
+ Or with [uv](https://github.com/astral-sh/uv):
127
+
128
+ ```bash
129
+ uv add django-whiteneuron
130
+ ```
131
+
132
+ ### Specific version from PyPI
133
+
134
+ ```bash
135
+ uv add "django-whiteneuron==0.2.37"
136
+ ```
137
+
138
+ ### From GitHub tag
139
+
140
+ ```bash
141
+ uv add "git+https://github.com/White-Neuron/django-whiteneuron.git@v0.2.37"
142
+ ```
143
+
144
+ ### From local source
145
+
146
+ ```bash
147
+ uv pip install -e .
148
+ ```
149
+
150
+ ## Django Configuration
151
+
152
+ Add the apps at the top of `INSTALLED_APPS`:
153
+
154
+ ```python
155
+ INSTALLED_APPS = [
156
+ "whiteneuron",
157
+ "whiteneuron.base",
158
+ "whiteneuron.feedbacks",
159
+ "whiteneuron.file_management",
160
+ "whiteneuron.contrib",
161
+ "whiteneuron.dashboard",
162
+ # ... your other apps
163
+ ]
164
+ ```
165
+
166
+ Add the required middleware **(order matters)**:
167
+
168
+ ```python
169
+ MIDDLEWARE = [
170
+ "django.middleware.security.SecurityMiddleware",
171
+ "whiteneuron.base.middleware.RateLimitMiddleware", # ← immediately after SecurityMiddleware
172
+ "whitenoise.middleware.WhiteNoiseMiddleware",
173
+ "django.contrib.sessions.middleware.SessionMiddleware",
174
+ "django.middleware.common.CommonMiddleware",
175
+ "django.middleware.csrf.CsrfViewMiddleware",
176
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
177
+ "django.contrib.messages.middleware.MessageMiddleware",
178
+ "django.middleware.clickjacking.XFrameOptionsMiddleware",
179
+ "whiteneuron.base.middleware.ReadonlyExceptionHandlerMiddleware",
180
+ "whiteneuron.base.middleware.UserActivityMiddleware", # ← after AuthenticationMiddleware
181
+ "whiteneuron.base.middleware.ThreadLocalMiddleware",
182
+ ]
183
+ ```
184
+
185
+ Set the custom user model:
186
+
187
+ ```python
188
+ AUTH_USER_MODEL = "base.User"
189
+ ```
190
+
191
+ ## UNFOLD Configuration Example
192
+
193
+ ```python
194
+ from django.templatetags.static import static
195
+ from django.utils.translation import gettext_lazy as _
196
+
197
+ UNFOLD = {
198
+ "SITE_HEADER": _("White Neuron"),
199
+ "SITE_TITLE": _("White Neuron Admin"),
200
+ "SITE_SUBHEADER": _("Admin panel"),
201
+ # Use SITE_ICON instead of SITE_LOGO to keep SITE_TITLE rendering correctly
202
+ "SITE_ICON": {
203
+ "light": lambda request: static("base/images/logo/WhiteNeuron.png"),
204
+ "dark": lambda request: static("base/images/logo/WhiteNeuron.png"),
205
+ },
206
+ "SITE_FAVICONS": [
207
+ {
208
+ "rel": "icon",
209
+ "sizes": "32x32",
210
+ "type": "image/svg+xml",
211
+ "href": lambda request: static("base/images/logo/WhiteNeuron.png"),
212
+ },
213
+ ],
214
+ "SHOW_HISTORY": False,
215
+ "SHOW_LANGUAGES": True,
216
+ "SHOW_VIEW_ON_SITE": True,
217
+ "SHOW_BACK_BUTTON": True,
218
+ "DASHBOARD_CALLBACK": "whiteneuron.dashboard.views.dashboard_callback",
219
+ "LOGIN": {
220
+ "image": lambda request: static("base/images/login-bg.jpg"),
221
+ },
222
+ "STYLES": [
223
+ lambda request: static("base/css/styles.css"),
224
+ lambda request: static("base/css/btn-styles.css"),
225
+ lambda request: static("base/css/loading.css"),
226
+ ],
227
+ "SCRIPTS": [
228
+ lambda request: static("base/js/loading.js"),
229
+ lambda request: static("base/js/whiteneuron.js"),
230
+ ],
231
+ "BORDER_RADIUS": "6px",
232
+ }
233
+ ```
234
+
235
+ ## Frontend (Tailwind 4 + daisyUI 5)
236
+
237
+ Install frontend dependencies:
238
+
239
+ ```bash
240
+ npm install -D @tailwindcss/cli@next daisyui@latest
241
+ ```
242
+
243
+ Build CSS using the provided script:
244
+
245
+ ```bash
246
+ bash scripts/tailwind.sh
247
+ ```
248
+
249
+ Or run directly:
250
+
251
+ ```bash
252
+ npx @tailwindcss/cli -i styles.css -o whiteneuron/static/base/css/styles.css --minify
253
+ ```
254
+
255
+ ## Running the Local Example
256
+
257
+ ```bash
258
+ cd whiteneuron
259
+ python manage.py migrate
260
+ python manage.py runserver
261
+ ```
262
+
263
+ Access the admin at: http://127.0.0.1:8000/admin/
264
+
265
+ ## Building the Package
266
+
267
+ ```bash
268
+ uv build
269
+ ```
270
+
271
+ Or use the all-in-one build script:
272
+
273
+ ```bash
274
+ bash scripts/build.sh
275
+ ```
276
+
277
+ ## Rate Limiting
278
+
279
+ `RateLimitMiddleware` limits by IP; `UserActivityMiddleware` limits by authenticated user. Redis is required for accuracy in multi-worker environments.
280
+
281
+ ```python
282
+ # settings.py (hoặc env)
283
+ RATE_LIMIT_REQUESTS = 60 # số request tối đa / window (theo IP)
284
+ RATE_LIMIT_WINDOW = 60 # tính bằng giây
285
+
286
+ USER_RATE_LIMIT_REQUESTS = 60 # theo user đã đăng nhập
287
+ USER_RATE_LIMIT_WINDOW = 60
288
+ ```
289
+
290
+ Corresponding env vars: `RATE_LIMIT_REQUESTS`, `RATE_LIMIT_WINDOW`, `USER_RATE_LIMIT_REQUESTS`, `USER_RATE_LIMIT_WINDOW`.
291
+
292
+ When the limit is exceeded:
293
+ - API requests (`/api/` or `Accept: application/json`) → JSON `{"detail": "Too many requests."}` with status 429.
294
+ - Browser requests → renders `429.html` template with `Retry-After` header.
295
+
296
+ ## IP Blacklist
297
+
298
+ Two protection layers operate in parallel. Both are checked before rate limiting and return 403 immediately.
299
+
300
+ ### Static — `.env` (CIDR ranges, infrastructure bans)
301
+
302
+ Loaded at startup, supports IPv4/IPv6 and CIDR:
303
+
304
+ ```env
305
+ # .env
306
+ IP_BLACKLIST=185.220.101.5,194.165.16.0/22,2001:db8::/32
307
+ ```
308
+
309
+ Requires a **Daphne/Gunicorn restart** to apply new entries.
310
+
311
+ ### Dynamic — Django Admin + Redis (real-time)
312
+
313
+ Managed via **System → IP Blacklist** in the admin panel (superuser only):
314
+
315
+ - **Permanent block**: leave `blocked_until` empty
316
+ - **Temporary block**: set `blocked_until` → Redis TTL auto-expires, no cron needed
317
+ - **Quick block from logs**: *User Activity* → select records → **Block IP address** action → Redis key set immediately, no restart needed
318
+
319
+ ```
320
+ Request → check static env blacklist (O(1))
321
+ → check cache.get('blacklist:dynamic:<ip>') (1 Redis GET)
322
+ → 403 nếu match, không tốn rate limit check
323
+ ```
324
+
325
+ ## Error Pages
326
+
327
+ Error templates live in `whiteneuron/templates/` and are used automatically by Django when `DEBUG=False`:
328
+
329
+ | Template | Error | Notes |
330
+ |---|---|---|
331
+ | `400.html` | Bad Request | |
332
+ | `403.html` | Forbidden | |
333
+ | `404.html` | Not Found | |
334
+ | `429.html` | Too Many Requests | Rendered manually by middleware, passes `{{ retry_after }}` |
335
+ | `500.html` | Server Error | |
336
+
337
+ No need to register `handler400/403/404/500` — Django resolves templates automatically via `APP_DIRS=True`.
338
+
339
+ ## Environment Configuration
340
+
341
+ Copy `env.example` to your environment file and update variables such as `DATABASE`, `REDIS`, `EMAIL`, and `ALLOWED_HOSTS`.
342
+
343
+ ## Contact
344
+
345
+ - Email: [anhnt@whiteneuron.com](mailto:anhnt@whiteneuron.com)
346
+ - Website: [https://whiteneuron.ai](https://whiteneuron.ai)
347
+ - GitHub: [https://github.com/White-Neuron/django-whiteneuron](https://github.com/White-Neuron/django-whiteneuron)
348
+
349
+ ## License
350
+
351
+ MIT License.
@@ -0,0 +1,265 @@
1
+ # django-whiteneuron
2
+
3
+ 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).
4
+
5
+ [![PyPI version](https://img.shields.io/pypi/v/django-whiteneuron)](https://pypi.org/project/django-whiteneuron/)
6
+ [![Python](https://img.shields.io/pypi/pyversions/django-whiteneuron)](https://pypi.org/project/django-whiteneuron/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
8
+ [![Downloads](https://img.shields.io/pypi/dm/django-whiteneuron)](https://pypi.org/project/django-whiteneuron/)
9
+
10
+ ![django-whiteneuron](https://raw.githubusercontent.com/White-Neuron/django-whiteneuron/main2.0/docs/images/main.png)
11
+
12
+ ## Current Version
13
+
14
+ - 0.3.1.2
15
+
16
+ ## Compatibility
17
+
18
+ - Python >= 3.11
19
+ - Django >= 5.2.13
20
+ - django-unfold >= 0.89.0
21
+ - Tailwind CSS 4.x + daisyUI 5.x (for the bundled frontend styles)
22
+
23
+ ## Changelog
24
+
25
+ See [CHANGELOG.md](CHANGELOG.md) for the full version history.
26
+
27
+ ### Latest: v0.3.1.2 (2026-04-16)
28
+ **Dependency: Bump django-unfold floor constraint to >=0.89.0**
29
+ - **Updated**: `pyproject.toml` — raised `django-unfold` minimum version from `>=0.85.0` to `>=0.89.0`; incorporates improvements from 0.86.0–0.89.0 (compressed fields by default, removal of unbound template blocks, inline before/after templates).
30
+ - **Updated**: `uv.lock` — lock file refreshed to reflect the updated constraint.
31
+
32
+ ## Installation
33
+
34
+ ### From PyPI (recommended)
35
+
36
+ ```bash
37
+ pip install django-whiteneuron
38
+ ```
39
+
40
+ Or with [uv](https://github.com/astral-sh/uv):
41
+
42
+ ```bash
43
+ uv add django-whiteneuron
44
+ ```
45
+
46
+ ### Specific version from PyPI
47
+
48
+ ```bash
49
+ uv add "django-whiteneuron==0.2.37"
50
+ ```
51
+
52
+ ### From GitHub tag
53
+
54
+ ```bash
55
+ uv add "git+https://github.com/White-Neuron/django-whiteneuron.git@v0.2.37"
56
+ ```
57
+
58
+ ### From local source
59
+
60
+ ```bash
61
+ uv pip install -e .
62
+ ```
63
+
64
+ ## Django Configuration
65
+
66
+ Add the apps at the top of `INSTALLED_APPS`:
67
+
68
+ ```python
69
+ INSTALLED_APPS = [
70
+ "whiteneuron",
71
+ "whiteneuron.base",
72
+ "whiteneuron.feedbacks",
73
+ "whiteneuron.file_management",
74
+ "whiteneuron.contrib",
75
+ "whiteneuron.dashboard",
76
+ # ... your other apps
77
+ ]
78
+ ```
79
+
80
+ Add the required middleware **(order matters)**:
81
+
82
+ ```python
83
+ MIDDLEWARE = [
84
+ "django.middleware.security.SecurityMiddleware",
85
+ "whiteneuron.base.middleware.RateLimitMiddleware", # ← immediately after SecurityMiddleware
86
+ "whitenoise.middleware.WhiteNoiseMiddleware",
87
+ "django.contrib.sessions.middleware.SessionMiddleware",
88
+ "django.middleware.common.CommonMiddleware",
89
+ "django.middleware.csrf.CsrfViewMiddleware",
90
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
91
+ "django.contrib.messages.middleware.MessageMiddleware",
92
+ "django.middleware.clickjacking.XFrameOptionsMiddleware",
93
+ "whiteneuron.base.middleware.ReadonlyExceptionHandlerMiddleware",
94
+ "whiteneuron.base.middleware.UserActivityMiddleware", # ← after AuthenticationMiddleware
95
+ "whiteneuron.base.middleware.ThreadLocalMiddleware",
96
+ ]
97
+ ```
98
+
99
+ Set the custom user model:
100
+
101
+ ```python
102
+ AUTH_USER_MODEL = "base.User"
103
+ ```
104
+
105
+ ## UNFOLD Configuration Example
106
+
107
+ ```python
108
+ from django.templatetags.static import static
109
+ from django.utils.translation import gettext_lazy as _
110
+
111
+ UNFOLD = {
112
+ "SITE_HEADER": _("White Neuron"),
113
+ "SITE_TITLE": _("White Neuron Admin"),
114
+ "SITE_SUBHEADER": _("Admin panel"),
115
+ # Use SITE_ICON instead of SITE_LOGO to keep SITE_TITLE rendering correctly
116
+ "SITE_ICON": {
117
+ "light": lambda request: static("base/images/logo/WhiteNeuron.png"),
118
+ "dark": lambda request: static("base/images/logo/WhiteNeuron.png"),
119
+ },
120
+ "SITE_FAVICONS": [
121
+ {
122
+ "rel": "icon",
123
+ "sizes": "32x32",
124
+ "type": "image/svg+xml",
125
+ "href": lambda request: static("base/images/logo/WhiteNeuron.png"),
126
+ },
127
+ ],
128
+ "SHOW_HISTORY": False,
129
+ "SHOW_LANGUAGES": True,
130
+ "SHOW_VIEW_ON_SITE": True,
131
+ "SHOW_BACK_BUTTON": True,
132
+ "DASHBOARD_CALLBACK": "whiteneuron.dashboard.views.dashboard_callback",
133
+ "LOGIN": {
134
+ "image": lambda request: static("base/images/login-bg.jpg"),
135
+ },
136
+ "STYLES": [
137
+ lambda request: static("base/css/styles.css"),
138
+ lambda request: static("base/css/btn-styles.css"),
139
+ lambda request: static("base/css/loading.css"),
140
+ ],
141
+ "SCRIPTS": [
142
+ lambda request: static("base/js/loading.js"),
143
+ lambda request: static("base/js/whiteneuron.js"),
144
+ ],
145
+ "BORDER_RADIUS": "6px",
146
+ }
147
+ ```
148
+
149
+ ## Frontend (Tailwind 4 + daisyUI 5)
150
+
151
+ Install frontend dependencies:
152
+
153
+ ```bash
154
+ npm install -D @tailwindcss/cli@next daisyui@latest
155
+ ```
156
+
157
+ Build CSS using the provided script:
158
+
159
+ ```bash
160
+ bash scripts/tailwind.sh
161
+ ```
162
+
163
+ Or run directly:
164
+
165
+ ```bash
166
+ npx @tailwindcss/cli -i styles.css -o whiteneuron/static/base/css/styles.css --minify
167
+ ```
168
+
169
+ ## Running the Local Example
170
+
171
+ ```bash
172
+ cd whiteneuron
173
+ python manage.py migrate
174
+ python manage.py runserver
175
+ ```
176
+
177
+ Access the admin at: http://127.0.0.1:8000/admin/
178
+
179
+ ## Building the Package
180
+
181
+ ```bash
182
+ uv build
183
+ ```
184
+
185
+ Or use the all-in-one build script:
186
+
187
+ ```bash
188
+ bash scripts/build.sh
189
+ ```
190
+
191
+ ## Rate Limiting
192
+
193
+ `RateLimitMiddleware` limits by IP; `UserActivityMiddleware` limits by authenticated user. Redis is required for accuracy in multi-worker environments.
194
+
195
+ ```python
196
+ # settings.py (hoặc env)
197
+ RATE_LIMIT_REQUESTS = 60 # số request tối đa / window (theo IP)
198
+ RATE_LIMIT_WINDOW = 60 # tính bằng giây
199
+
200
+ USER_RATE_LIMIT_REQUESTS = 60 # theo user đã đăng nhập
201
+ USER_RATE_LIMIT_WINDOW = 60
202
+ ```
203
+
204
+ Corresponding env vars: `RATE_LIMIT_REQUESTS`, `RATE_LIMIT_WINDOW`, `USER_RATE_LIMIT_REQUESTS`, `USER_RATE_LIMIT_WINDOW`.
205
+
206
+ When the limit is exceeded:
207
+ - API requests (`/api/` or `Accept: application/json`) → JSON `{"detail": "Too many requests."}` with status 429.
208
+ - Browser requests → renders `429.html` template with `Retry-After` header.
209
+
210
+ ## IP Blacklist
211
+
212
+ Two protection layers operate in parallel. Both are checked before rate limiting and return 403 immediately.
213
+
214
+ ### Static — `.env` (CIDR ranges, infrastructure bans)
215
+
216
+ Loaded at startup, supports IPv4/IPv6 and CIDR:
217
+
218
+ ```env
219
+ # .env
220
+ IP_BLACKLIST=185.220.101.5,194.165.16.0/22,2001:db8::/32
221
+ ```
222
+
223
+ Requires a **Daphne/Gunicorn restart** to apply new entries.
224
+
225
+ ### Dynamic — Django Admin + Redis (real-time)
226
+
227
+ Managed via **System → IP Blacklist** in the admin panel (superuser only):
228
+
229
+ - **Permanent block**: leave `blocked_until` empty
230
+ - **Temporary block**: set `blocked_until` → Redis TTL auto-expires, no cron needed
231
+ - **Quick block from logs**: *User Activity* → select records → **Block IP address** action → Redis key set immediately, no restart needed
232
+
233
+ ```
234
+ Request → check static env blacklist (O(1))
235
+ → check cache.get('blacklist:dynamic:<ip>') (1 Redis GET)
236
+ → 403 nếu match, không tốn rate limit check
237
+ ```
238
+
239
+ ## Error Pages
240
+
241
+ Error templates live in `whiteneuron/templates/` and are used automatically by Django when `DEBUG=False`:
242
+
243
+ | Template | Error | Notes |
244
+ |---|---|---|
245
+ | `400.html` | Bad Request | |
246
+ | `403.html` | Forbidden | |
247
+ | `404.html` | Not Found | |
248
+ | `429.html` | Too Many Requests | Rendered manually by middleware, passes `{{ retry_after }}` |
249
+ | `500.html` | Server Error | |
250
+
251
+ No need to register `handler400/403/404/500` — Django resolves templates automatically via `APP_DIRS=True`.
252
+
253
+ ## Environment Configuration
254
+
255
+ Copy `env.example` to your environment file and update variables such as `DATABASE`, `REDIS`, `EMAIL`, and `ALLOWED_HOSTS`.
256
+
257
+ ## Contact
258
+
259
+ - Email: [anhnt@whiteneuron.com](mailto:anhnt@whiteneuron.com)
260
+ - Website: [https://whiteneuron.ai](https://whiteneuron.ai)
261
+ - GitHub: [https://github.com/White-Neuron/django-whiteneuron](https://github.com/White-Neuron/django-whiteneuron)
262
+
263
+ ## License
264
+
265
+ MIT License.