django-whiteneuron 0.2.36__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. django_whiteneuron-0.2.36.dist-info/METADATA +382 -0
  2. django_whiteneuron-0.2.36.dist-info/RECORD +172 -0
  3. django_whiteneuron-0.2.36.dist-info/WHEEL +5 -0
  4. django_whiteneuron-0.2.36.dist-info/licenses/LICENSE +21 -0
  5. django_whiteneuron-0.2.36.dist-info/top_level.txt +1 -0
  6. whiteneuron/__init__.py +0 -0
  7. whiteneuron/base/__init__.py +0 -0
  8. whiteneuron/base/admin.py +751 -0
  9. whiteneuron/base/apps.py +8 -0
  10. whiteneuron/base/asgi.py +33 -0
  11. whiteneuron/base/ckeditor.py +12 -0
  12. whiteneuron/base/filters.py +18 -0
  13. whiteneuron/base/forms.py +12 -0
  14. whiteneuron/base/management/__init__.py +0 -0
  15. whiteneuron/base/management/commands/__init__.py +0 -0
  16. whiteneuron/base/management/commands/init_admin.py +106 -0
  17. whiteneuron/base/management/commands/init_groupuser.py +83 -0
  18. whiteneuron/base/management/commands/init_guest.py +32 -0
  19. whiteneuron/base/middleware.py +371 -0
  20. whiteneuron/base/migrations/0001_initial.py +132 -0
  21. whiteneuron/base/migrations/0002_imagemodel_userprofile_user_avatar_user_biography_and_more.py +421 -0
  22. whiteneuron/base/migrations/0003_notification_obj_link.py +18 -0
  23. whiteneuron/base/migrations/0004_delete_notification.py +16 -0
  24. whiteneuron/base/migrations/0005_user_show_softdelete.py +18 -0
  25. whiteneuron/base/migrations/0006_user_is_bot.py +18 -0
  26. whiteneuron/base/migrations/0007_app.py +28 -0
  27. whiteneuron/base/migrations/0008_app_created_at_app_created_by_app_deleted_at_and_more.py +56 -0
  28. whiteneuron/base/migrations/0009_alter_app_table.py +17 -0
  29. whiteneuron/base/migrations/0010_app_category.py +18 -0
  30. whiteneuron/base/migrations/0011_alter_app_options.py +17 -0
  31. whiteneuron/base/migrations/0012_app_permission.py +18 -0
  32. whiteneuron/base/migrations/0013_app_thumbnail_url.py +18 -0
  33. whiteneuron/base/migrations/0014_alter_app_created_at_alter_app_updated_at_and_more.py +44 -0
  34. whiteneuron/base/migrations/0015_ipblacklist.py +33 -0
  35. whiteneuron/base/migrations/__init__.py +0 -0
  36. whiteneuron/base/modeladmin.py +478 -0
  37. whiteneuron/base/models.py +868 -0
  38. whiteneuron/base/resources.py +0 -0
  39. whiteneuron/base/settings.py +832 -0
  40. whiteneuron/base/sites.py +13 -0
  41. whiteneuron/base/tasks.py +4 -0
  42. whiteneuron/base/templatetags/__init__.py +0 -0
  43. whiteneuron/base/templatetags/unfold_list_custom.py +10 -0
  44. whiteneuron/base/templatetags/wn_filters.py +8 -0
  45. whiteneuron/base/tests.py +46 -0
  46. whiteneuron/base/thread_local.py +2 -0
  47. whiteneuron/base/urls.py +26 -0
  48. whiteneuron/base/utils.py +360 -0
  49. whiteneuron/base/views.py +13 -0
  50. whiteneuron/base/widgets.py +29 -0
  51. whiteneuron/contrib/__init__.py +0 -0
  52. whiteneuron/contrib/wn_import_export/__init__.py +14 -0
  53. whiteneuron/contrib/wn_import_export/admin.py +67 -0
  54. whiteneuron/contrib/wn_import_export/constants.py +1 -0
  55. whiteneuron/contrib/wn_import_export/mixins.py +2 -0
  56. whiteneuron/contrib/wn_import_export/tasks.py +40 -0
  57. whiteneuron/contrib/wn_import_export/utils.py +16 -0
  58. whiteneuron/contrib/wn_modeltranslation/__init__.py +8 -0
  59. whiteneuron/contrib/wn_modeltranslation/admin.py +48 -0
  60. whiteneuron/contrib/wn_modeltranslation/utils.py +81 -0
  61. whiteneuron/dashboard/__init__.py +0 -0
  62. whiteneuron/dashboard/admin.py +3 -0
  63. whiteneuron/dashboard/apps.py +8 -0
  64. whiteneuron/dashboard/migrations/__init__.py +0 -0
  65. whiteneuron/dashboard/models.py +3 -0
  66. whiteneuron/dashboard/tests.py +3 -0
  67. whiteneuron/dashboard/views.py +304 -0
  68. whiteneuron/feedbacks/__init__.py +0 -0
  69. whiteneuron/feedbacks/admin.py +127 -0
  70. whiteneuron/feedbacks/apps.py +8 -0
  71. whiteneuron/feedbacks/migrations/0001_initial.py +79 -0
  72. whiteneuron/feedbacks/migrations/0002_feedbackdata_created_by_feedbackdata_deleted_at_and_more.py +81 -0
  73. whiteneuron/feedbacks/migrations/0003_feedbackdata_note.py +23 -0
  74. whiteneuron/feedbacks/migrations/0004_alter_feedbackdata_object_id.py +18 -0
  75. whiteneuron/feedbacks/migrations/0005_feedbackdata_field.py +18 -0
  76. whiteneuron/feedbacks/migrations/0006_alter_feedbackdata_created_at_and_more.py +24 -0
  77. whiteneuron/feedbacks/migrations/__init__.py +0 -0
  78. whiteneuron/feedbacks/models.py +72 -0
  79. whiteneuron/feedbacks/tests.py +3 -0
  80. whiteneuron/feedbacks/urls.py +69 -0
  81. whiteneuron/feedbacks/utils.py +5 -0
  82. whiteneuron/feedbacks/views.py +3 -0
  83. whiteneuron/file_management/__init__.py +0 -0
  84. whiteneuron/file_management/admin.py +32 -0
  85. whiteneuron/file_management/apps.py +7 -0
  86. whiteneuron/file_management/migrations/0001_initial.py +198 -0
  87. whiteneuron/file_management/migrations/0002_alter_excelfile_options_alter_pdffile_options_and_more.py +74 -0
  88. whiteneuron/file_management/migrations/0003_alter_excelfile_created_at_and_more.py +34 -0
  89. whiteneuron/file_management/migrations/__init__.py +0 -0
  90. whiteneuron/file_management/models.py +65 -0
  91. whiteneuron/file_management/tests.py +3 -0
  92. whiteneuron/file_management/utils.py +8 -0
  93. whiteneuron/file_management/views.py +3 -0
  94. whiteneuron/locale/vi/LC_MESSAGES/django.mo +0 -0
  95. whiteneuron/locale/vi/LC_MESSAGES/django.po +1038 -0
  96. whiteneuron/manage.py +22 -0
  97. whiteneuron/notification/__init__.py +0 -0
  98. whiteneuron/notification/admin.py +205 -0
  99. whiteneuron/notification/apps.py +7 -0
  100. whiteneuron/notification/consumers.py +18 -0
  101. whiteneuron/notification/management/__init__.py +0 -0
  102. whiteneuron/notification/management/commands/__init__.py +0 -0
  103. whiteneuron/notification/management/commands/call_demo_noti.py +11 -0
  104. whiteneuron/notification/migrations/0001_initial.py +93 -0
  105. whiteneuron/notification/migrations/0002_alter_notificationconfig_event_type.py +27 -0
  106. whiteneuron/notification/migrations/0003_notification.py +73 -0
  107. whiteneuron/notification/migrations/0004_alter_notification_flag.py +27 -0
  108. whiteneuron/notification/migrations/0005_notification_keywords.py +18 -0
  109. whiteneuron/notification/migrations/0006_remove_notification_keywords.py +17 -0
  110. whiteneuron/notification/migrations/0007_notification_changed_data.py +18 -0
  111. whiteneuron/notification/migrations/0008_alter_notification_changed_data.py +18 -0
  112. whiteneuron/notification/migrations/0009_notification_action_by_alter_notification_user.py +26 -0
  113. whiteneuron/notification/migrations/0010_alter_notification_user.py +21 -0
  114. whiteneuron/notification/migrations/0011_alter_notification_user.py +21 -0
  115. whiteneuron/notification/migrations/0012_alter_notification_action_and_more.py +73 -0
  116. whiteneuron/notification/migrations/__init__.py +0 -0
  117. whiteneuron/notification/models.py +118 -0
  118. whiteneuron/notification/routing.py +6 -0
  119. whiteneuron/notification/tests.py +3 -0
  120. whiteneuron/notification/utils.py +11 -0
  121. whiteneuron/notification/views.py +23 -0
  122. whiteneuron/static/base/css/btn-styles.css +62 -0
  123. whiteneuron/static/base/css/ckeditor5.css +550 -0
  124. whiteneuron/static/base/css/loading.css +18 -0
  125. whiteneuron/static/base/css/styles.css +2 -0
  126. whiteneuron/static/base/forms/css/html-editor.css +89 -0
  127. whiteneuron/static/base/forms/js/format.html.js +171 -0
  128. whiteneuron/static/base/forms/js/trix.config.js +257 -0
  129. whiteneuron/static/base/images/delete.svg +1 -0
  130. whiteneuron/static/base/images/edit.svg +3 -0
  131. whiteneuron/static/base/images/icon-viewlink.svg +3 -0
  132. whiteneuron/static/base/images/loading.gif +0 -0
  133. whiteneuron/static/base/images/login-bg.jpg +0 -0
  134. whiteneuron/static/base/images/login_bg.jpg +0 -0
  135. whiteneuron/static/base/images/logo/WhiteNeuron.png +0 -0
  136. whiteneuron/static/base/js/chart.min.js +19 -0
  137. whiteneuron/static/base/js/d3.v7.min.js +2 -0
  138. whiteneuron/static/base/js/loading.js +179 -0
  139. whiteneuron/static/base/js/whiteneuron.js +39 -0
  140. whiteneuron/synchronization/__init__.py +0 -0
  141. whiteneuron/synchronization/admin.py +3 -0
  142. whiteneuron/synchronization/apps.py +6 -0
  143. whiteneuron/synchronization/migrations/__init__.py +0 -0
  144. whiteneuron/synchronization/models.py +29 -0
  145. whiteneuron/synchronization/tests.py +3 -0
  146. whiteneuron/synchronization/views.py +3 -0
  147. whiteneuron/templates/400.html +72 -0
  148. whiteneuron/templates/403.html +72 -0
  149. whiteneuron/templates/404.html +76 -0
  150. whiteneuron/templates/429.html +77 -0
  151. whiteneuron/templates/500.html +74 -0
  152. whiteneuron/templates/admin/auth/user/add_form.html +5 -0
  153. whiteneuron/templates/admin/base/image_change_form.html +30 -0
  154. whiteneuron/templates/admin/base/userprofile_change_form.html +11 -0
  155. whiteneuron/templates/admin/base.html +15 -0
  156. whiteneuron/templates/admin/change_list.html +59 -0
  157. whiteneuron/templates/admin/feedbacks/feedback_change_form.html +41 -0
  158. whiteneuron/templates/admin/grid_view_results.html +139 -0
  159. whiteneuron/templates/admin/header.html +32 -0
  160. whiteneuron/templates/admin/index.html +97 -0
  161. whiteneuron/templates/admin/login.html +56 -0
  162. whiteneuron/templates/admin/login_after.html +21 -0
  163. whiteneuron/templates/admin/search_form.html +60 -0
  164. whiteneuron/templates/admin/submit_line.html +67 -0
  165. whiteneuron/templates/base/forms/helpers/toolbar.html +108 -0
  166. whiteneuron/templates/base/forms/wysiwyg.html +15 -0
  167. whiteneuron/templates/base.html +81 -0
  168. whiteneuron/templates/unfold/helpers/account_links.html +126 -0
  169. whiteneuron/templates/unfold/helpers/app_list_badge.html +53 -0
  170. whiteneuron/templates/unfold/helpers/field_password.html +26 -0
  171. whiteneuron/templates/unfold/helpers/navigation_user.html +41 -0
  172. whiteneuron/templates/unfold/helpers/pagination.html +14 -0
@@ -0,0 +1,382 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-whiteneuron
3
+ Version: 0.2.36
4
+ Summary: django-whiteneuron là một gói mở rộng giúp nâng cấp giao diện và chức năng Django Admin, mang đến trải nghiệm quản trị hiện đại, trực quan và tối ưu hiệu suất. 🚀
5
+ Author-email: White Neuron <anhnt@whiteneuron.com>
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://github.com/White-Neuron/django-whiteneuron
29
+ Project-URL: repository, https://github.com/White-Neuron/django-whiteneuron
30
+ Keywords: django,plugin,admin,dashboard,whiteneuron
31
+ Classifier: Development Status :: 4 - Beta
32
+ Classifier: Intended Audience :: Developers
33
+ Classifier: Framework :: Django
34
+ Classifier: Framework :: Django :: 5.0
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Programming Language :: Python :: 3.11
37
+ Classifier: Programming Language :: Python :: 3.12
38
+ Classifier: License :: OSI Approved :: MIT License
39
+ Classifier: Operating System :: OS Independent
40
+ Requires-Python: >=3.11
41
+ Description-Content-Type: text/markdown
42
+ License-File: LICENSE
43
+ Requires-Dist: django-debug-toolbar>=5.0.1
44
+ Requires-Dist: django>=5.1.6
45
+ Requires-Dist: django-celery-beat>=2.7.0
46
+ Requires-Dist: django-guardian>=2.4.0
47
+ Requires-Dist: django-imagekit>=5.0.0
48
+ Requires-Dist: django-import-export>=4.3.3
49
+ Requires-Dist: django-modeltranslation>=0.19.11
50
+ Requires-Dist: django-ninja>=1.3.0
51
+ Requires-Dist: django-simple-history>=3.8.0
52
+ Requires-Dist: gunicorn>=23.0.0
53
+ Requires-Dist: hiredis>=3.1.0
54
+ Requires-Dist: markdown>=3.7
55
+ Requires-Dist: openai>=1.58.1
56
+ Requires-Dist: openpyxl>=3.1.5
57
+ Requires-Dist: pandas>=2.2.3
58
+ Requires-Dist: pillow>=11.0.0
59
+ Requires-Dist: python-dotenv>=1.0.1
60
+ Requires-Dist: redis>=5.2.1
61
+ Requires-Dist: sentry-sdk==2.28.0
62
+ Requires-Dist: django-browser-reload>=1.18.0
63
+ Requires-Dist: whitenoise>=6.9.0
64
+ Requires-Dist: django-crispy-forms>=2.4
65
+ Requires-Dist: django-colorfield>=0.14.0
66
+ Requires-Dist: channels>=4.2.2
67
+ Requires-Dist: channels-redis>=4.2.1
68
+ Requires-Dist: uvicorn>=0.34.3
69
+ Requires-Dist: daphne>=4.2.0
70
+ Requires-Dist: django-ckeditor-5>=0.2.18
71
+ Requires-Dist: django-cors-headers>=4.3.0
72
+ Requires-Dist: django-unfold>=0.85.0
73
+ Requires-Dist: djangoql>=0.18.1
74
+ Provides-Extra: dev
75
+ Requires-Dist: pytest; extra == "dev"
76
+ Requires-Dist: black; extra == "dev"
77
+ Requires-Dist: flake8; extra == "dev"
78
+ Requires-Dist: pre-commit; extra == "dev"
79
+ Dynamic: license-file
80
+
81
+ # django-whiteneuron
82
+
83
+ django-whiteneuron là package mở rộng Django Admin theo hướng hiện đại, tập trung vào UI/UX quản trị, dashboard, feedback, file management và các tích hợp admin nâng cao.
84
+
85
+ ## Phiên bản hiện tại
86
+
87
+ - 0.2.36
88
+
89
+ ## Tương thích
90
+
91
+ - Python >= 3.11
92
+ - Django >= 5.1.6
93
+ - django-unfold >= 0.85.0
94
+ - Tailwind CSS 4.x + daisyUI 5.x (khi dùng bộ style frontend đi kèm)
95
+
96
+ ## Changelog
97
+
98
+ ### v0.2.36 (2026-03-30) — latest
99
+ **Security: init_admin — xoá hardcode password, sinh mật khẩu ngẫu nhiên, gửi email tự động**
100
+ - **Security**: Xoá password hardcode `'wnadmin2024&'` khỏi `init_admin.py` — thay bằng `secrets.choice()` (CSPRNG) sinh mật khẩu 20 ký tự (chữ hoa, thường, số, ký tự đặc biệt).
101
+ - **Added**: Hỗ trợ `INIT_ADMIN_PASSWORD` env var — ưu tiên dùng password cố định từ `.env`, nếu không có thì sinh ngẫu nhiên.
102
+ - **Added**: Hỗ trợ `INIT_ADMIN_EMAIL` env var — email nhận mật khẩu tạm thời, bắt buộc phải có (không còn hardcode).
103
+ - **Added**: Tự động gửi email mật khẩu qua `send_email_login()` với template chuẩn (chữ ký công ty, link đăng nhập) khi password là random.
104
+ - **Added**: Flag `--reset-password` cho lệnh `init_admin` — đặt lại mật khẩu admin đã tồn tại mà không ảnh hưởng luồng CI/CD bình thường.
105
+ - **Fixed**: Double DB write khi tạo user mới — chỉ 1 lần `save()` duy nhất.
106
+ - **Fixed**: Validate email trước khi ghi password vào DB — tránh password bị đổi nhưng email gửi thất bại.
107
+ - **Improved**: `send_email_login()` thêm param `is_reset` — subject email thay đổi theo ngữ cảnh (tạo mới vs đặt lại).
108
+ - **Removed**: File `templates/admin/base/email_password.html` không dùng.
109
+
110
+ ### v0.2.35 (2026-03-29)
111
+ **Dynamic IP Blacklist: Redis + Model + Admin**
112
+ - **Added**: `IPBlacklist` model (`base/ip_blacklists`) — quản lý IP bị chặn real-time qua Django Admin, hỗ trợ block vĩnh viễn và tạm thời (`blocked_until` với Redis TTL tự expire).
113
+ - **Added**: `IPBlacklistAdmin` — giao diện quản lý IP blacklist với actions Activate/Deactivate, hiện thị trong sidebar System dưới icon `block`, superuser only.
114
+ - **Added**: Action **"Block IP address"** trong `UserActivityAdmin` — chọn bản ghi activity → block IP ngay lập tức vào Redis, không cần restart Daphne.
115
+ - **Improved**: `RateLimitMiddleware._is_blacklisted()` kiểm tra thêm `cache.get('blacklist:dynamic:<ip>')` sau static env blacklist — hybrid hai lớp tĩnh + động.
116
+ - **Added**: Migration `base/0015_ipblacklist.py`.
117
+
118
+ ### v0.2.34 (2026-03-29)
119
+ **IP Blacklist: chặn IP/CIDR vĩnh viễn qua `.env`**
120
+ - **Added**: `RateLimitMiddleware` bổ sung `_is_blacklisted()` — kiểm tra IP/CIDR blacklist trước rate limit, trả 403 ngay lập tức cho IP bị block.
121
+ - **Added**: Parse `IP_BLACKLIST` từ settings (comma-separated IPs và/hoặc CIDR), hỗ trợ cả IPv4 và IPv6 — single IP dùng `set` lookup O(1), CIDR range dùng `ip_network` match.
122
+ - **Added**: Setting `IP_BLACKLIST` trong `settings.py` và biến tương ứng trong `env.example`.
123
+
124
+ ### v0.2.33 (2026-03-29)
125
+ **Rate Limiting fix cho Docker + Daphne**
126
+ - **Fixed**: `_is_rate_limited()` và `_is_user_rate_limited()` thêm `except Exception: return False` — bắt `ConnectionError` khi Redis không reachable trong Docker (trước đây unhandled exception làm request crash hoặc bypass rate limit).
127
+ - **Fixed**: Default `RATE_LIMIT_REQUESTS` hạ từ 300 → 60 req/60 s, `USER_RATE_LIMIT_REQUESTS` từ 200 → 60 — phù hợp với admin panel.
128
+ - **Fixed**: `User.display_header()` dùng `reverse('admin:base_user_change')` thay vì hardcode `/admin/base/user/` — tránh broken link khi đổi admin prefix.
129
+ - **Fixed**: Default `BEHIND_CLOUDFLARE=True` vì luôn deploy qua Cloudflare Tunnel.
130
+
131
+ ### v0.2.32 (2026-03-29)
132
+ **Security hardening & Gunicorn production readiness**
133
+ - **Security**: `get_client_ip()` chỉ tin tưởng `CF-Connecting-IP` / `True-Client-IP` khi `BEHIND_CLOUDFLARE=True` — tránh bypass rate limit qua header giả mạo.
134
+ - **Fixed**: `UserActivityMiddleware.__call__()` cache kết quả `do_not_track()` vào `skip` — tránh gọi 2 lần mỗi request.
135
+ - **Removed**: `import logging` không dùng trong middleware.py.
136
+
137
+ ### v0.2.31 (2026-03-29)
138
+ **Rate Limiting, Security Hardening & Error Pages**
139
+ - **Added**: `RateLimitMiddleware` — global IP-based rate limiting (300 req/60 s mặc định) đặt ngay sau `SecurityMiddleware`, hoạt động cả trên API lẫn browser.
140
+ - **Improved**: `UserActivityMiddleware` bổ sung per-user rate limiting (200 req/60 s mặc định).
141
+ - **Added**: `/ws/` vào `exclude_paths` của `UserActivityMiddleware` — WS handshake không bị log và không tính vào rate limit.
142
+ - **Security**: Sanitize `POST` data trước khi ghi vào `UserActivity` — mask các field nhạy cảm (password, token, api_key…).
143
+ - **Security**: Chuyển sang pattern `cache.incr()` first (atomic trên Redis) tránh race condition.
144
+ - **Added**: Template lỗi đầy đủ: `400.html`, `403.html`, `404.html`, `429.html`, `500.html`.
145
+ - **Added**: `base.html` skeleton tối giản cho các trang lỗi — không phụ thuộc file static ngoài.
146
+ - **Added**: Cảnh báo startup khi production chạy không có Redis (rate limit không chính xác trên multi-worker).
147
+
148
+ ### v0.2.30 (2026-03-29)
149
+ - **Improved**: `AppAdmin.get_queryset()` chỉ trả về các app active mà user thực sự có quyền truy cập.
150
+ - **Improved**: `superuser` vẫn giữ nguyên quyền nhìn thấy toàn bộ app active.
151
+
152
+ ### v0.2.29 (2026-03-28)
153
+ - **Fixed**: `NotificationAdmin` không còn bị lỗi 403 khi bấm `View Linked Object`.
154
+ - **Improved**: Action xem đối tượng liên kết được route riêng qua detail action, tương thích tốt hơn với Unfold.
155
+ - **Improved**: Bổ sung xử lý an toàn khi notification không có `obj_link`.
156
+
157
+ ### v0.2.28 (2026-03-28)
158
+ - **Improved**: Giao diện grid view của user/app dùng icon trực quan hơn cho role và trạng thái.
159
+ - **Improved**: Chuẩn hóa `verbose_name` cho nhiều field trong `Notification` và `NotificationConfig`.
160
+ - **Added**: Migration `notification/0012` đồng bộ metadata field-level.
161
+
162
+ ### v0.2.27 và trước
163
+ Xem chi tiết tại [releases](https://github.com/White-Neuron/django-whiteneuron/releases).
164
+
165
+ ## Cài đặt (ưu tiên uv)
166
+
167
+ Package chưa phát hành lên PyPI.
168
+
169
+ ### Cài từ GitHub theo tag
170
+
171
+ ```bash
172
+ uv add "git+https://github.com/White-Neuron/django-whiteneuron.git@v0.2.35"
173
+ ```
174
+
175
+ ### Cài từ source local
176
+
177
+ ```bash
178
+ uv pip install -e .
179
+ ```
180
+
181
+ ## Cấu hình Django cơ bản
182
+
183
+ Thêm các app vào đầu INSTALLED_APPS:
184
+
185
+ ```python
186
+ INSTALLED_APPS = [
187
+ "whiteneuron",
188
+ "whiteneuron.base",
189
+ "whiteneuron.feedbacks",
190
+ "whiteneuron.file_management",
191
+ "whiteneuron.contrib",
192
+ "whiteneuron.dashboard",
193
+ # ... các app khác
194
+ ]
195
+ ```
196
+
197
+ Thêm middleware cần thiết (thứ tự quan trọng):
198
+
199
+ ```python
200
+ MIDDLEWARE = [
201
+ "django.middleware.security.SecurityMiddleware",
202
+ "whiteneuron.base.middleware.RateLimitMiddleware", # ← ngay sau SecurityMiddleware
203
+ "whitenoise.middleware.WhiteNoiseMiddleware",
204
+ "django.contrib.sessions.middleware.SessionMiddleware",
205
+ "django.middleware.common.CommonMiddleware",
206
+ "django.middleware.csrf.CsrfViewMiddleware",
207
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
208
+ "django.contrib.messages.middleware.MessageMiddleware",
209
+ "django.middleware.clickjacking.XFrameOptionsMiddleware",
210
+ "whiteneuron.base.middleware.ReadonlyExceptionHandlerMiddleware",
211
+ "whiteneuron.base.middleware.UserActivityMiddleware", # ← sau AuthenticationMiddleware
212
+ "whiteneuron.base.middleware.ThreadLocalMiddleware",
213
+ ]
214
+ ```
215
+
216
+ Thiết lập user model:
217
+
218
+ ```python
219
+ AUTH_USER_MODEL = "base.User"
220
+ ```
221
+
222
+ ## Cấu hình UNFOLD mẫu
223
+
224
+ ```python
225
+ from django.templatetags.static import static
226
+ from django.utils.translation import gettext_lazy as _
227
+
228
+ UNFOLD = {
229
+ "SITE_HEADER": _("White Neuron"),
230
+ "SITE_TITLE": _("White Neuron Admin"),
231
+ "SITE_SUBHEADER": _("Admin panel"),
232
+ # Dùng SITE_ICON thay vì SITE_LOGO để giữ SITE_TITLE hiển thị đúng
233
+ "SITE_ICON": {
234
+ "light": lambda request: static("base/images/logo/WhiteNeuron.png"),
235
+ "dark": lambda request: static("base/images/logo/WhiteNeuron.png"),
236
+ },
237
+ "SITE_FAVICONS": [
238
+ {
239
+ "rel": "icon",
240
+ "sizes": "32x32",
241
+ "type": "image/svg+xml",
242
+ "href": lambda request: static("base/images/logo/WhiteNeuron.png"),
243
+ },
244
+ ],
245
+ "SHOW_HISTORY": False,
246
+ "SHOW_LANGUAGES": True,
247
+ "SHOW_VIEW_ON_SITE": True,
248
+ "SHOW_BACK_BUTTON": True,
249
+ "DASHBOARD_CALLBACK": "whiteneuron.dashboard.views.dashboard_callback",
250
+ "LOGIN": {
251
+ "image": lambda request: static("base/images/login-bg.jpg"),
252
+ },
253
+ "STYLES": [
254
+ lambda request: static("base/css/styles.css"),
255
+ lambda request: static("base/css/btn-styles.css"),
256
+ lambda request: static("base/css/loading.css"),
257
+ ],
258
+ "SCRIPTS": [
259
+ lambda request: static("base/js/loading.js"),
260
+ lambda request: static("base/js/whiteneuron.js"),
261
+ ],
262
+ "BORDER_RADIUS": "6px",
263
+ }
264
+ ```
265
+
266
+ ## Frontend (Tailwind 4 + daisyUI 5)
267
+
268
+ Cài dependencies frontend:
269
+
270
+ ```bash
271
+ npm install -D @tailwindcss/cli@next daisyui@latest
272
+ ```
273
+
274
+ Build CSS bằng script có sẵn:
275
+
276
+ ```bash
277
+ bash scripts/tailwind.sh
278
+ ```
279
+
280
+ Hoặc chạy trực tiếp:
281
+
282
+ ```bash
283
+ npx @tailwindcss/cli -i styles.css -o whiteneuron/static/base/css/styles.css --minify
284
+ ```
285
+
286
+ ## Chạy local package example
287
+
288
+ ```bash
289
+ cd whiteneuron
290
+ python manage.py migrate
291
+ python manage.py runserver
292
+ ```
293
+
294
+ Truy cập admin tại: http://127.0.0.1:8000/admin/
295
+
296
+ ## Build package
297
+
298
+ ```bash
299
+ uv build
300
+ ```
301
+
302
+ Hoặc dùng script build tổng hợp:
303
+
304
+ ```bash
305
+ bash scripts/build.sh
306
+ ```
307
+
308
+ ## Rate Limiting
309
+
310
+ `RateLimitMiddleware` giới hạn theo IP, `UserActivityMiddleware` giới hạn theo user đã đăng nhập. Cần Redis để hoạt động chính xác trên môi trường multi-worker.
311
+
312
+ ```python
313
+ # settings.py (hoặc env)
314
+ RATE_LIMIT_REQUESTS = 60 # số request tối đa / window (theo IP)
315
+ RATE_LIMIT_WINDOW = 60 # tính bằng giây
316
+
317
+ USER_RATE_LIMIT_REQUESTS = 60 # theo user đã đăng nhập
318
+ USER_RATE_LIMIT_WINDOW = 60
319
+ ```
320
+
321
+ Các biến env tương ứng: `RATE_LIMIT_REQUESTS`, `RATE_LIMIT_WINDOW`, `USER_RATE_LIMIT_REQUESTS`, `USER_RATE_LIMIT_WINDOW`.
322
+
323
+ Khi vượt ngưỡng:
324
+ - Request API (`/api/` hoặc `Accept: application/json`) → JSON `{"detail": "Too many requests."}` với status 429.
325
+ - Request browser → render template `429.html` với header `Retry-After`.
326
+
327
+ ## IP Blacklist
328
+
329
+ Hai lớp bảo vệ hoạt động song song. Cả hai đều được kiểm tra trước rate limit, trả 403 ngay lập tức.
330
+
331
+ ### Tĩnh — `.env` (CIDR ranges, infra bans)
332
+
333
+ Load lúc khởi động, hỗ trợ IPv4/IPv6 và CIDR:
334
+
335
+ ```env
336
+ # .env
337
+ IP_BLACKLIST=185.220.101.5,194.165.16.0/22,2001:db8::/32
338
+ ```
339
+
340
+ Cần **restart Daphne/Gunicorn** để apply khi thêm entry mới.
341
+
342
+ ### Động — Django Admin + Redis (real-time)
343
+
344
+ Quản lý qua **System → IP Blacklist** trong admin panel (superuser only):
345
+
346
+ - **Block vĩnh viễn**: để trống `blocked_until`
347
+ - **Block tạm thời**: set `blocked_until` → Redis TTL tự expire, không cần cron
348
+ - **Block nhanh từ logs**: *User Activity* → chọn records → action **Block IP address** → Redis key set ngay, không restart
349
+
350
+ ```
351
+ Request → check static env blacklist (O(1))
352
+ → check cache.get('blacklist:dynamic:<ip>') (1 Redis GET)
353
+ → 403 nếu match, không tốn rate limit check
354
+ ```
355
+
356
+ ## Error Pages
357
+
358
+ Các template lỗi nằm trong `whiteneuron/templates/` và được Django tự động sử dụng khi `DEBUG=False`:
359
+
360
+ | Template | Lỗi | Ghi chú |
361
+ |---|---|---|
362
+ | `400.html` | Bad Request | |
363
+ | `403.html` | Forbidden | |
364
+ | `404.html` | Not Found | |
365
+ | `429.html` | Too Many Requests | Render thủ công bởi middleware, truyền `{{ retry_after }}` |
366
+ | `500.html` | Server Error | |
367
+
368
+ Không cần đăng ký `handler400/403/404/500` — Django tự tìm template qua `APP_DIRS=True`.
369
+
370
+ ## Môi trường cấu hình
371
+
372
+ Copy env.example thành file môi trường phù hợp cho dự án của bạn và cập nhật các biến như DATABASE, REDIS, EMAIL, ALLOWED_HOSTS.
373
+
374
+ ## Liên hệ
375
+
376
+ - Email: [anhnt@whiteneuron.com](mailto:anhnt@whiteneuron.com)
377
+ - Website: [https://whiteneuron.ai](https://whiteneuron.ai)
378
+ - GitHub: [https://github.com/White-Neuron/django-whiteneuron](https://github.com/White-Neuron/django-whiteneuron)
379
+
380
+ ## License
381
+
382
+ MIT License.
@@ -0,0 +1,172 @@
1
+ django_whiteneuron-0.2.36.dist-info/licenses/LICENSE,sha256=pQdQpd6YdP6SFTjblJSZdALQS-ToHlrx0Nr6wi7aBtI,1073
2
+ whiteneuron/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ whiteneuron/manage.py,sha256=MFkiZrRhf6-QLpU-BmX92Z_QVEylLYkgjlhFnnUypwE,672
4
+ whiteneuron/base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ whiteneuron/base/admin.py,sha256=MGQXq8E0hxKHdo9f1HnUyQWrzElwsoWF_iN60OTojcQ,28238
6
+ whiteneuron/base/apps.py,sha256=SDXHeO6OjO388OebT1DH4hW6XKYh94CKh_92kIx8qcc,236
7
+ whiteneuron/base/asgi.py,sha256=JXVRqj0NDb9FWYa_Wzry7HkPq24inz3u3OIhElOiASk,935
8
+ whiteneuron/base/ckeditor.py,sha256=xshns8vPQZCO0aZSOz71G0W6t02CrO_85LMzzmBdouA,366
9
+ whiteneuron/base/filters.py,sha256=EF0tQmJCf9qL2VcN6C-fSTRM-DyiCRE2GjbGO0ym238,647
10
+ whiteneuron/base/forms.py,sha256=gWcSTAHsDpLLL9X2kxY2vGDFKwhKt5yC09_jS3wrylM,386
11
+ whiteneuron/base/middleware.py,sha256=-1ynOJDc0SGtWDIZ3LS4Q0H1AS5HfhIMgb_npYL-hXo,14258
12
+ whiteneuron/base/modeladmin.py,sha256=vjw3IdHSoMJ6zOXSdUNBFGJWedFs38YOOhRkCwK3yio,21579
13
+ whiteneuron/base/models.py,sha256=iEmvPErJLkP9vg7_aU2E8xY8CcZSLBJ5fG--2exZsaU,34288
14
+ whiteneuron/base/resources.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ whiteneuron/base/settings.py,sha256=IYoDoKtrLJ1UqrZjSDtGcyalqlBmxM1F4J1e5eLE730,31151
16
+ whiteneuron/base/sites.py,sha256=_gN_ZWo6NYOfdIKc1s6Qe8reNngi35qNaCKM_pPKBJU,261
17
+ whiteneuron/base/tasks.py,sha256=ANbzjRiygwV1iCpFNDd0yjrNFnH6mmVUpp-BQC75R8k,78
18
+ whiteneuron/base/tests.py,sha256=NSZRkzmreD4aKfoJ7Y0bR9sYVJJTMjgSg5J88EjHedY,1326
19
+ whiteneuron/base/thread_local.py,sha256=yo4CJSH6e4JtlkkZvTVYpdsoxVDYf1soCaK-JTCZnPA,49
20
+ whiteneuron/base/urls.py,sha256=UFpoRfW9sF9dECutjz3Bon-loaUv_K88RmXTMxJo__M,713
21
+ whiteneuron/base/utils.py,sha256=a7GQY1Dx9npsXLyqqx2RwKLWl9geeu4ifjGFq8JOOUM,12529
22
+ whiteneuron/base/views.py,sha256=M3C0LcXrNtGBjKQKISvsVfu7JzjxgwNw6cFpX6-Hhjs,405
23
+ whiteneuron/base/widgets.py,sha256=L2-Ca-UN7sgvR_Q2IW_RuUUgvltV_tma7GVVcdCWoqI,908
24
+ whiteneuron/base/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
+ whiteneuron/base/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
+ whiteneuron/base/management/commands/init_admin.py,sha256=kSfE8RQcnBqCwOpfq265Jk2mBTJzN3zan9JGu97FxZg,4406
27
+ whiteneuron/base/management/commands/init_groupuser.py,sha256=9a2IDOO-rUIJJOY_ipmSwltpVfm_wCwu43z9tlgdEAw,2504
28
+ whiteneuron/base/management/commands/init_guest.py,sha256=IuHIrxUnIFJFWePZwR3KElyZ0iIDosW620fQRS2sG0w,1159
29
+ whiteneuron/base/migrations/0001_initial.py,sha256=1GoONj5LsJE1CQcFg-3F4CGC9p78jYpynUiJvJr6RfU,4825
30
+ whiteneuron/base/migrations/0002_imagemodel_userprofile_user_avatar_user_biography_and_more.py,sha256=Y1iXJyuQF4IbrkjtOe_-UW6U7bsTZwAaBwqrK4jVdUo,14976
31
+ whiteneuron/base/migrations/0003_notification_obj_link.py,sha256=-J4-kO2G4zAquQCoCmkmbIjFl2tyJ6Lhc87dSns91gE,453
32
+ whiteneuron/base/migrations/0004_delete_notification.py,sha256=a36IP8XlylMY_AV-ptSq1aOOc0bOiktN99M3hz0XNV4,301
33
+ whiteneuron/base/migrations/0005_user_show_softdelete.py,sha256=u7x_h4Tpc2jwU5Rxi4Td5JMTqA64Wcmn5VJcNM6p_MI,479
34
+ whiteneuron/base/migrations/0006_user_is_bot.py,sha256=9mrmiwLSRIiA9mcgCaAq3D2PmC6uihXzOALIGwfJsTI,464
35
+ whiteneuron/base/migrations/0007_app.py,sha256=SNCmeddLt8f4r9X5GRGStmAZKUSThKPzRr_c1YORGf4,1024
36
+ whiteneuron/base/migrations/0008_app_created_at_app_created_by_app_deleted_at_and_more.py,sha256=88JX18ucCQ0_6qxzqqC0ucmr1kSipIDRlWMS0j5DkpA,2093
37
+ whiteneuron/base/migrations/0009_alter_app_table.py,sha256=Qka5dXsxVCSQGLRYjnbrNNOsLg1zrBJWlFevvS7yoZo,352
38
+ whiteneuron/base/migrations/0010_app_category.py,sha256=c90KnUv_KZkGBLGiJaP4WFywP5C1WW1QFA47LKxKSl4,426
39
+ whiteneuron/base/migrations/0011_alter_app_options.py,sha256=u-zxRHX2_fvJfv4j7EZ8S-v4MLKRF11EexpaI6C9IGI,385
40
+ whiteneuron/base/migrations/0012_app_permission.py,sha256=QvQ9xGffj-KeS754NwHXQ_IQbe7bIsFFlq8xCgSxsXw,484
41
+ whiteneuron/base/migrations/0013_app_thumbnail_url.py,sha256=fdRvNu7itvrM10jB4e3LY6OF35Qy9wEGTmVXOl8QTTs,418
42
+ whiteneuron/base/migrations/0014_alter_app_created_at_alter_app_updated_at_and_more.py,sha256=mK91tSFHrKievM3blYJLRQwapyectiIzxn3DMKv8QLo,1692
43
+ whiteneuron/base/migrations/0015_ipblacklist.py,sha256=EkpGPrvobzoMKd8sIzODrL0vl5uLHxxaVuOF2Ne635k,1691
44
+ whiteneuron/base/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
+ whiteneuron/base/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
+ whiteneuron/base/templatetags/unfold_list_custom.py,sha256=Doo018bsWLheFqPtFeV_dtmuTJQy9e-zXIfxcIb0ICo,360
47
+ whiteneuron/base/templatetags/wn_filters.py,sha256=H6ctlQiaORJeyksIwwBhYjypi3XA2ZtOvYHo-YQqonQ,197
48
+ whiteneuron/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
+ whiteneuron/contrib/wn_import_export/__init__.py,sha256=1VSp418u319z3vZ5FI6UN_-cSsbmflvUUdp01Q7e1Q4,339
50
+ whiteneuron/contrib/wn_import_export/admin.py,sha256=Q7em3D1in4vYtBu3DgUXLMXjmUu30_qcmLB3lwGX6iE,3063
51
+ whiteneuron/contrib/wn_import_export/constants.py,sha256=qXVpk6ToY3RqrY9HyUz-sLiiqb7t_IZSrfxPGX-wHZw,129
52
+ whiteneuron/contrib/wn_import_export/mixins.py,sha256=QPfA5tjSOZ_2JEDTyvv-FLwqLyUNFPQCZANhopuTVqY,41
53
+ whiteneuron/contrib/wn_import_export/tasks.py,sha256=HoPBTi6PTWRfEz_u7MiJYAG1oBoglyaaiKRwQAssoBU,1357
54
+ whiteneuron/contrib/wn_import_export/utils.py,sha256=LK2MLxxPNRHmzRsugfrRQoLGtMD-bNrDLTaHJH4ZylU,661
55
+ whiteneuron/contrib/wn_modeltranslation/__init__.py,sha256=JnzvdXWPJsyGYJSuyKxt_Y1s8Pp-LP1dKMBUdOkuWmE,146
56
+ whiteneuron/contrib/wn_modeltranslation/admin.py,sha256=WHyOf6pP2ta_Ewu10yf6ffFcCcdeXLhDEMbe4o1zy9M,1655
57
+ whiteneuron/contrib/wn_modeltranslation/utils.py,sha256=MAtJPnEgxsXiI2iE6U0vhjMwJe7sIh9NG0dss3iIHhI,2796
58
+ whiteneuron/dashboard/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
+ whiteneuron/dashboard/admin.py,sha256=suMo4x8I3JBxAFBVIdE-5qnqZ6JAZV0FESABHOSc-vg,63
60
+ whiteneuron/dashboard/apps.py,sha256=F0QFA8hzuR2Gyo6LI9fQNz6I8E47WK1mYkDGNHRbMNg,251
61
+ whiteneuron/dashboard/models.py,sha256=Vjc0p2XbAPgE6HyTF6vll98A4eDhA5AvaQqsc4kQ9AQ,57
62
+ whiteneuron/dashboard/tests.py,sha256=mrbGGRNg5jwbTJtWWa7zSKdDyeB4vmgZCRc2nk6VY-g,60
63
+ whiteneuron/dashboard/views.py,sha256=95ZRVTxn76F-oiGRcoWIIhZ9cwinvIvulgiNaLK6XqU,13621
64
+ whiteneuron/dashboard/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
65
+ whiteneuron/feedbacks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
+ whiteneuron/feedbacks/admin.py,sha256=QHiH91cIwhsNoIGgaMQI4fVdYCUYoDbBKjMKkpMq8Pg,4611
67
+ whiteneuron/feedbacks/apps.py,sha256=w8jJ_JWZRQyztHCJqctoHrejpjp84vw8T6cnhASBN30,251
68
+ whiteneuron/feedbacks/models.py,sha256=gCCZpUWH_OXpdBxetyeKExe07SYxXXBN5aFQJ81MEXY,1795
69
+ whiteneuron/feedbacks/tests.py,sha256=mrbGGRNg5jwbTJtWWa7zSKdDyeB4vmgZCRc2nk6VY-g,60
70
+ whiteneuron/feedbacks/urls.py,sha256=pZvPi2__0-vI4NJdxtNcQFAhRJFSvSyzfXt_Tx3vZUk,2694
71
+ whiteneuron/feedbacks/utils.py,sha256=1H2AU8wrjM-Gpuikq-wHdyAl9PmXflX9GrM973BRCTM,185
72
+ whiteneuron/feedbacks/views.py,sha256=xc1IQHrsij7j33TUbo-_oewy3vs03pw_etpBWaMYJl0,63
73
+ whiteneuron/feedbacks/migrations/0001_initial.py,sha256=IymFI7oDof0zasE6M6CMs9m5LoMjQo3zovjdwyDTCDs,2627
74
+ whiteneuron/feedbacks/migrations/0002_feedbackdata_created_by_feedbackdata_deleted_at_and_more.py,sha256=78dYQYJs1cV5K4UYlDUojJW4P5P0gB4FAlfmYlot1rY,2621
75
+ whiteneuron/feedbacks/migrations/0003_feedbackdata_note.py,sha256=XYAvBD4BbQiPNzGfSNLbx_NI6wtI8co_7A4M03_hjPU,577
76
+ whiteneuron/feedbacks/migrations/0004_alter_feedbackdata_object_id.py,sha256=tVbeeVW_WGAmQVo8E41ixA8oQa4X1lrqtzNI6Y8RYuQ,423
77
+ whiteneuron/feedbacks/migrations/0005_feedbackdata_field.py,sha256=g010tFftZzl6s9b-ImH6SGfv5o0ewIdL5BqwssXhPYY,515
78
+ whiteneuron/feedbacks/migrations/0006_alter_feedbackdata_created_at_and_more.py,sha256=qtAGFl-f5C4loNY3uYtG1jv6gjwjStUSmSlQuj8Nwvs,758
79
+ whiteneuron/feedbacks/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
80
+ whiteneuron/file_management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
81
+ whiteneuron/file_management/admin.py,sha256=g-gx9wNvfKI0gQbbdNuAYsTMx_RXCXncO3YgrpAZse8,1103
82
+ whiteneuron/file_management/apps.py,sha256=mhGNjf2xMrtABOjoFr9t9nSKs5srNFpN0F7J7x-HVTw,267
83
+ whiteneuron/file_management/models.py,sha256=rxoEQhQaWnJFZ1NHgCIUnPUx56XbYU0ghuT-ki0qpvA,2336
84
+ whiteneuron/file_management/tests.py,sha256=mrbGGRNg5jwbTJtWWa7zSKdDyeB4vmgZCRc2nk6VY-g,60
85
+ whiteneuron/file_management/utils.py,sha256=Swg6BTPdU5-L6Xjwt8zYTyTSC0566_Exvp7ykwT_jE0,271
86
+ whiteneuron/file_management/views.py,sha256=xc1IQHrsij7j33TUbo-_oewy3vs03pw_etpBWaMYJl0,63
87
+ whiteneuron/file_management/migrations/0001_initial.py,sha256=BLLIe3UVkcoiKP8FfmTFBwgy0JMo3VYhWgVUP3nWc34,7241
88
+ whiteneuron/file_management/migrations/0002_alter_excelfile_options_alter_pdffile_options_and_more.py,sha256=M82DrcbrnOi9mdCqhjJ_eyjGdy7fjrlf4wgRhWvfhg0,2341
89
+ whiteneuron/file_management/migrations/0003_alter_excelfile_created_at_and_more.py,sha256=-a5p-GrwYHoYQiGleDHuTmZ32UCvubRbL63RO-MPrHI,1278
90
+ whiteneuron/file_management/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
+ whiteneuron/locale/vi/LC_MESSAGES/django.mo,sha256=UvhC_kxUA6YwgAOLrIoLwt5x2IewjN52UlR9Vh0p8do,15547
92
+ whiteneuron/locale/vi/LC_MESSAGES/django.po,sha256=Z__JM8U_Y1QXFZ6tWdp-Ixxv9WrQq3wqahdS4j36h-s,23583
93
+ whiteneuron/notification/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
94
+ whiteneuron/notification/admin.py,sha256=iqmMBncI2xVmK6AXMQyOkn_iH6CVcUqSn27n7gFO1e4,7188
95
+ whiteneuron/notification/apps.py,sha256=3viYZZXJadjuPO671o9NApVxM1qTiraUpsYLau0xaNk,259
96
+ whiteneuron/notification/consumers.py,sha256=QmqOlrGL6ga_NC0kvxec7nRfh-hbWrkhf3bCVgNKjDI,656
97
+ whiteneuron/notification/models.py,sha256=mZ7G9qgFHtLy5AxyFORSrOuW2R-Gldi1VG4qBUsQZxU,4542
98
+ whiteneuron/notification/routing.py,sha256=kGEdljcl0ONcJlMkxFplTafgNcQQ5LafbgHIlJJ-a5s,154
99
+ whiteneuron/notification/tests.py,sha256=mrbGGRNg5jwbTJtWWa7zSKdDyeB4vmgZCRc2nk6VY-g,60
100
+ whiteneuron/notification/utils.py,sha256=n6FGdAkzflkJkQF_1PTQWfxIkPM2f2XI0IuLEx2gGF4,338
101
+ whiteneuron/notification/views.py,sha256=_BW_5m_xvCcRatM4woVJqnm7tnbHV7Fp1O6oDYS36pg,730
102
+ whiteneuron/notification/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
103
+ whiteneuron/notification/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
104
+ whiteneuron/notification/management/commands/call_demo_noti.py,sha256=0ox4m89sZoDwlRe5_YrZKyRKZH0o1U0uLYXsWckoLcg,432
105
+ whiteneuron/notification/migrations/0001_initial.py,sha256=mihTPepFj-75nGqeqEgLbfhn5GnZ2vybStmy4xqItQM,3262
106
+ whiteneuron/notification/migrations/0002_alter_notificationconfig_event_type.py,sha256=UGBEEeUroJON2SaREnseBcB5KJ_YKXhb4ektq-zA5_g,750
107
+ whiteneuron/notification/migrations/0003_notification.py,sha256=XMpYxseq-CYQONGtfMd7t8zR571EQi7oSY_khFf7D50,2514
108
+ whiteneuron/notification/migrations/0004_alter_notification_flag.py,sha256=D5nAl9Eq8JwDC6jw1O7thsVF0Gr6DMABCD03wvPHJWw,673
109
+ whiteneuron/notification/migrations/0005_notification_keywords.py,sha256=QfRVyaxZ08BZRGvDmoBeLIsdMZ5Sms9WWrxWcG3G3lw,426
110
+ whiteneuron/notification/migrations/0006_remove_notification_keywords.py,sha256=NjDRKx7C6HZgo9JHmuKqqvyG4cTRLOf2-8rGcBepdpY,344
111
+ whiteneuron/notification/migrations/0007_notification_changed_data.py,sha256=2asf_BZksSc63mP3SEve5aZOaBhk26QBvxC2I_J8jzs,448
112
+ whiteneuron/notification/migrations/0008_alter_notification_changed_data.py,sha256=AkvM3wBmBnb_RmN0x6SlXsVcOkmxDq0_JOlbAy_kMPc,447
113
+ whiteneuron/notification/migrations/0009_notification_action_by_alter_notification_user.py,sha256=jXZlfIDG-cMygpnwJ4k_FnAN3QA-QLQTJG480sU1H5Y,973
114
+ whiteneuron/notification/migrations/0010_alter_notification_user.py,sha256=hXAlLJuV2hgc8yjlzj-0cMrYjvsmVhV4__pBAPrSJvM,638
115
+ whiteneuron/notification/migrations/0011_alter_notification_user.py,sha256=WyriEbUf2deMJVdV8tj9K-65EnljvURb1bN1Fv2aLlM,625
116
+ whiteneuron/notification/migrations/0012_alter_notification_action_and_more.py,sha256=2f2LJtvPxe-XxERpYe-_rirx_n60gINWURxIFH-fWT0,3666
117
+ whiteneuron/notification/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
118
+ whiteneuron/static/base/css/btn-styles.css,sha256=fwe9AbHBfdw6CEpo2xdjOITI3V34_4fvP7zpgHqKatQ,1171
119
+ whiteneuron/static/base/css/ckeditor5.css,sha256=NVV2YptMDYebXseQBxyfye0zrXbFf-FHX938N4iQBYY,17165
120
+ whiteneuron/static/base/css/loading.css,sha256=Ul1IQkgco5hoFlXUrPtcH5HiBjxm2ZHcx0J6DpCTymE,333
121
+ whiteneuron/static/base/css/styles.css,sha256=7V8-aEGVG0EaPXuOf8knxB9XBeDSnT5VaaOC4yUl3gw,69556
122
+ whiteneuron/static/base/forms/css/html-editor.css,sha256=t5_hSwTsXt-9-I6NhTZsVO13cKPUPFPtscqOdHWKXM0,2083
123
+ whiteneuron/static/base/forms/js/format.html.js,sha256=nfnxOaWGisucocuxMnVeT8upb8CwsUwTb29d6hud_rE,5743
124
+ whiteneuron/static/base/forms/js/trix.config.js,sha256=SiO8_agB7BV4GXpOcoltdpi584Z3XsHtblk8ho5FY0U,10410
125
+ whiteneuron/static/base/images/delete.svg,sha256=2v1EWSlV52v_KERJrYPYRf8aPLMyCwgub1WuzBKfiuQ,621
126
+ whiteneuron/static/base/images/edit.svg,sha256=ojfxOFDKdrMtJKQOK8UMuxfjGWSOQWBMCberMrvmVA4,634
127
+ whiteneuron/static/base/images/icon-viewlink.svg,sha256=NL7fcy7mQOQ91sRzxoVRLfzWzXBRU59cFANOrGOwWM0,581
128
+ whiteneuron/static/base/images/loading.gif,sha256=Nn042HtXGr50n8obGNXVQyC37SsSYhmTmJ3_nrI-7TQ,29295
129
+ whiteneuron/static/base/images/login-bg.jpg,sha256=ftRIsX4R3BgEDwsFQn-Z0r7MEjhd5C9AFLHQ53tmy5k,171252
130
+ whiteneuron/static/base/images/login_bg.jpg,sha256=sklTmSFmyjpmf6gMwDCTx5k6BhJAvgdpBFJRqDqZ9SI,796446
131
+ whiteneuron/static/base/images/logo/WhiteNeuron.png,sha256=ZwR9hw5KZX_k5U1hYzJqG4CX8JhqV-vGuDgh8yOi1QY,187526
132
+ whiteneuron/static/base/js/chart.min.js,sha256=mybVbDz8ML_jzdHwyG01P5nUSWtIihdUmVsPvMUBowY,203426
133
+ whiteneuron/static/base/js/d3.v7.min.js,sha256=8glLv2FBs1lyLE_kVOtsSw8OQswQzHr5IfwVj864ZTk,279706
134
+ whiteneuron/static/base/js/loading.js,sha256=h9TyJ07RR4V102nqWKKnluWC4rxlK2MI08CnweZKOIc,5448
135
+ whiteneuron/static/base/js/whiteneuron.js,sha256=Dc4XiElNyyAaUz43ZBVohSVu_XDCgeGSuGYXCgQ2c-4,1522
136
+ whiteneuron/synchronization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
137
+ whiteneuron/synchronization/admin.py,sha256=suMo4x8I3JBxAFBVIdE-5qnqZ6JAZV0FESABHOSc-vg,63
138
+ whiteneuron/synchronization/apps.py,sha256=fb07n9CS6wLQXyvpUNW71PMI0xKFQez5pn4D_D_j_8s,174
139
+ whiteneuron/synchronization/models.py,sha256=WqKP8hQYmR2jvN-fHLcPUpJaF3n0SBUSuozkKGaPrLo,1326
140
+ whiteneuron/synchronization/tests.py,sha256=mrbGGRNg5jwbTJtWWa7zSKdDyeB4vmgZCRc2nk6VY-g,60
141
+ whiteneuron/synchronization/views.py,sha256=xc1IQHrsij7j33TUbo-_oewy3vs03pw_etpBWaMYJl0,63
142
+ whiteneuron/synchronization/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
143
+ whiteneuron/templates/400.html,sha256=lSJYB4PM8BMu8Yod7t5131mAh16F6RALfutChAwmJjs,4467
144
+ whiteneuron/templates/403.html,sha256=Sa84WpDvX25G66JAQ-LNX3xAsmixrfhVu7nOf1X_a8g,4487
145
+ whiteneuron/templates/404.html,sha256=X2Abk2Gzlhsa2Mgx5OPpw484taZDssNGNa3QjJQ5GGU,4655
146
+ whiteneuron/templates/429.html,sha256=PZnlHluTnz2MdkKYELOec44Tracf9F2J2bmcI_qwmZk,4810
147
+ whiteneuron/templates/500.html,sha256=la1MmPxqRskjpzQ-SkiJzvkRwoi8d9rWxtftzM2HuOw,4614
148
+ whiteneuron/templates/base.html,sha256=hnugWukai3yv9av3bco39TD3EUzYNpQKIUl5Iufq8O8,2159
149
+ whiteneuron/templates/admin/base.html,sha256=UPCQE0PzmpOLHirBYMDNblaPKMw6ugAOJdFFt2owK_s,374
150
+ whiteneuron/templates/admin/change_list.html,sha256=CLyP6e_FSghXWa9Ymb_aktlW1so9CY7-BwRM9o3QTQE,1823
151
+ whiteneuron/templates/admin/grid_view_results.html,sha256=WGfB1lFKf84GJQesFSx1ps7VINeXOX7lTNPFYHGJt6Q,7419
152
+ whiteneuron/templates/admin/header.html,sha256=mrayYWCVN3oJ1tJLV9gSiL7IbuTuHtksRzEWHQ6AV5U,1567
153
+ whiteneuron/templates/admin/index.html,sha256=OD9fdIaPEREwEwhT-vZRiNDMpA9yYNTCZadHSQe8N5A,4587
154
+ whiteneuron/templates/admin/login.html,sha256=w6TqiH_xngZtYg3x-Ee_1d2QuDmhSQsw1DNO9ACNzJw,2423
155
+ whiteneuron/templates/admin/login_after.html,sha256=-RpVIgA1NofBW2AshtM0tOvjP2jsxD087WFqDq5upgA,989
156
+ whiteneuron/templates/admin/search_form.html,sha256=KyMI-yzd_CgQXNQih67xIDpVkgvrFAOFjCrb0lGd4ZA,4270
157
+ whiteneuron/templates/admin/submit_line.html,sha256=yKQZxNzFRXXGPyOv61dl2_Mvmc8KPdcjO18psLgvx7c,3042
158
+ whiteneuron/templates/admin/auth/user/add_form.html,sha256=beYUPZQ3pcwGwUTT9a9fF6p6z8Qw_91maUw2tWd1nPY,99
159
+ whiteneuron/templates/admin/base/image_change_form.html,sha256=mTUkq94QnjoQZ8-vywORuHz4H20YbW_XeUDbogmD_JI,933
160
+ whiteneuron/templates/admin/base/userprofile_change_form.html,sha256=HtSRBTGsVmlzX3L0tJmhV_pHK0HtxQRC1gJ0qIvzS_c,195
161
+ whiteneuron/templates/admin/feedbacks/feedback_change_form.html,sha256=XEKNKlWjliApPkCfTn0kXiJhtBD-HyGuy1bkM2k3BgA,1728
162
+ whiteneuron/templates/base/forms/wysiwyg.html,sha256=VwvlrUSirW2cOucb3SUSocozONsjJeZs_25CoXJGhJA,927
163
+ whiteneuron/templates/base/forms/helpers/toolbar.html,sha256=-28w1YoiuWtbwVjkxD__eCz-qrWgZZPPWOi5r8bhVes,9392
164
+ whiteneuron/templates/unfold/helpers/account_links.html,sha256=CaEtqfAAX_fYHh_oeSop2t2fTwJrkoayWLRUwW8g77M,6268
165
+ whiteneuron/templates/unfold/helpers/app_list_badge.html,sha256=utd0QPDlr6wrLSO8KKIWr9Cx2m7ea-bROprAqLd_qTY,2265
166
+ whiteneuron/templates/unfold/helpers/field_password.html,sha256=JZSHfMlp-8lpdMYIvytd_OYdkecZcNWiaJJH0mmHwnw,1081
167
+ whiteneuron/templates/unfold/helpers/navigation_user.html,sha256=KM36ESy6UZPI4joY2g7e2yJZYwfI5sHxgdk5P8dzaMg,2204
168
+ whiteneuron/templates/unfold/helpers/pagination.html,sha256=_7gtaE7lSWQwonTejStWTDWmkdk4osZ4gdXY__DzIjM,1205
169
+ django_whiteneuron-0.2.36.dist-info/METADATA,sha256=1ZtcdEyk9OG_DPQ2sukqtjGs5SOdW-9DyZoLD1ywBjI,16392
170
+ django_whiteneuron-0.2.36.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
171
+ django_whiteneuron-0.2.36.dist-info/top_level.txt,sha256=QAzlimDggQc4cTuulOy1y8Jbd8_xKmrjpZvglniGtBU,12
172
+ django_whiteneuron-0.2.36.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Nguyễn Tú Anh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ whiteneuron
File without changes
File without changes