django-nativemojo 0.1.10__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_nativemojo-0.1.10/LICENSE +19 -0
  2. django_nativemojo-0.1.10/NOTICE +8 -0
  3. django_nativemojo-0.1.10/PKG-INFO +96 -0
  4. django_nativemojo-0.1.10/README.md +66 -0
  5. django_nativemojo-0.1.10/mojo/__init__.py +3 -0
  6. django_nativemojo-0.1.10/mojo/apps/account/__init__.py +1 -0
  7. django_nativemojo-0.1.10/mojo/apps/account/admin.py +91 -0
  8. django_nativemojo-0.1.10/mojo/apps/account/apps.py +16 -0
  9. django_nativemojo-0.1.10/mojo/apps/account/migrations/0001_initial.py +77 -0
  10. django_nativemojo-0.1.10/mojo/apps/account/migrations/0002_user_is_email_verified_user_is_phone_verified.py +23 -0
  11. django_nativemojo-0.1.10/mojo/apps/account/migrations/0003_group_mojo_secrets_user_mojo_secrets.py +23 -0
  12. django_nativemojo-0.1.10/mojo/apps/account/migrations/__init__.py +0 -0
  13. django_nativemojo-0.1.10/mojo/apps/account/models/__init__.py +3 -0
  14. django_nativemojo-0.1.10/mojo/apps/account/models/group.py +98 -0
  15. django_nativemojo-0.1.10/mojo/apps/account/models/member.py +95 -0
  16. django_nativemojo-0.1.10/mojo/apps/account/models/pkey.py +18 -0
  17. django_nativemojo-0.1.10/mojo/apps/account/models/user.py +211 -0
  18. django_nativemojo-0.1.10/mojo/apps/account/rest/__init__.py +3 -0
  19. django_nativemojo-0.1.10/mojo/apps/account/rest/group.py +25 -0
  20. django_nativemojo-0.1.10/mojo/apps/account/rest/user.py +47 -0
  21. django_nativemojo-0.1.10/mojo/apps/account/utils/__init__.py +0 -0
  22. django_nativemojo-0.1.10/mojo/apps/account/utils/jwtoken.py +72 -0
  23. django_nativemojo-0.1.10/mojo/apps/account/utils/passkeys.py +54 -0
  24. django_nativemojo-0.1.10/mojo/apps/fileman/README.md +549 -0
  25. django_nativemojo-0.1.10/mojo/apps/fileman/__init__.py +0 -0
  26. django_nativemojo-0.1.10/mojo/apps/fileman/apps.py +15 -0
  27. django_nativemojo-0.1.10/mojo/apps/fileman/backends/__init__.py +117 -0
  28. django_nativemojo-0.1.10/mojo/apps/fileman/backends/base.py +319 -0
  29. django_nativemojo-0.1.10/mojo/apps/fileman/backends/filesystem.py +397 -0
  30. django_nativemojo-0.1.10/mojo/apps/fileman/backends/s3.py +398 -0
  31. django_nativemojo-0.1.10/mojo/apps/fileman/examples/configurations.py +378 -0
  32. django_nativemojo-0.1.10/mojo/apps/fileman/examples/usage_example.py +665 -0
  33. django_nativemojo-0.1.10/mojo/apps/fileman/management/__init__.py +1 -0
  34. django_nativemojo-0.1.10/mojo/apps/fileman/management/commands/__init__.py +1 -0
  35. django_nativemojo-0.1.10/mojo/apps/fileman/management/commands/cleanup_expired_uploads.py +222 -0
  36. django_nativemojo-0.1.10/mojo/apps/fileman/models/__init__.py +7 -0
  37. django_nativemojo-0.1.10/mojo/apps/fileman/models/file.py +292 -0
  38. django_nativemojo-0.1.10/mojo/apps/fileman/models/manager.py +227 -0
  39. django_nativemojo-0.1.10/mojo/apps/fileman/models/render.py +0 -0
  40. django_nativemojo-0.1.10/mojo/apps/fileman/rest/__init__ +0 -0
  41. django_nativemojo-0.1.10/mojo/apps/fileman/rest/__init__.py +23 -0
  42. django_nativemojo-0.1.10/mojo/apps/fileman/rest/fileman.py +13 -0
  43. django_nativemojo-0.1.10/mojo/apps/fileman/rest/upload.py +92 -0
  44. django_nativemojo-0.1.10/mojo/apps/fileman/utils/__init__.py +19 -0
  45. django_nativemojo-0.1.10/mojo/apps/fileman/utils/upload.py +616 -0
  46. django_nativemojo-0.1.10/mojo/apps/incident/__init__.py +1 -0
  47. django_nativemojo-0.1.10/mojo/apps/incident/handlers/__init__.py +3 -0
  48. django_nativemojo-0.1.10/mojo/apps/incident/handlers/event_handlers.py +142 -0
  49. django_nativemojo-0.1.10/mojo/apps/incident/migrations/0001_initial.py +83 -0
  50. django_nativemojo-0.1.10/mojo/apps/incident/migrations/0002_rename_bundle_ruleset_bundle_minutes_event_hostname_and_more.py +44 -0
  51. django_nativemojo-0.1.10/mojo/apps/incident/migrations/0003_alter_event_model_id.py +18 -0
  52. django_nativemojo-0.1.10/mojo/apps/incident/migrations/0004_alter_incident_model_id.py +18 -0
  53. django_nativemojo-0.1.10/mojo/apps/incident/migrations/__init__.py +0 -0
  54. django_nativemojo-0.1.10/mojo/apps/incident/models/__init__.py +3 -0
  55. django_nativemojo-0.1.10/mojo/apps/incident/models/event.py +135 -0
  56. django_nativemojo-0.1.10/mojo/apps/incident/models/incident.py +33 -0
  57. django_nativemojo-0.1.10/mojo/apps/incident/models/rule.py +247 -0
  58. django_nativemojo-0.1.10/mojo/apps/incident/parsers/__init__.py +0 -0
  59. django_nativemojo-0.1.10/mojo/apps/incident/parsers/ossec/__init__.py +1 -0
  60. django_nativemojo-0.1.10/mojo/apps/incident/parsers/ossec/core.py +82 -0
  61. django_nativemojo-0.1.10/mojo/apps/incident/parsers/ossec/parsed.py +23 -0
  62. django_nativemojo-0.1.10/mojo/apps/incident/parsers/ossec/rules.py +124 -0
  63. django_nativemojo-0.1.10/mojo/apps/incident/parsers/ossec/utils.py +169 -0
  64. django_nativemojo-0.1.10/mojo/apps/incident/reporter.py +42 -0
  65. django_nativemojo-0.1.10/mojo/apps/incident/rest/__init__.py +2 -0
  66. django_nativemojo-0.1.10/mojo/apps/incident/rest/event.py +23 -0
  67. django_nativemojo-0.1.10/mojo/apps/incident/rest/ossec.py +22 -0
  68. django_nativemojo-0.1.10/mojo/apps/logit/__init__.py +0 -0
  69. django_nativemojo-0.1.10/mojo/apps/logit/admin.py +37 -0
  70. django_nativemojo-0.1.10/mojo/apps/logit/migrations/0001_initial.py +32 -0
  71. django_nativemojo-0.1.10/mojo/apps/logit/migrations/0002_log_duid_log_payload_log_username.py +28 -0
  72. django_nativemojo-0.1.10/mojo/apps/logit/migrations/0003_log_level.py +18 -0
  73. django_nativemojo-0.1.10/mojo/apps/logit/migrations/__init__.py +0 -0
  74. django_nativemojo-0.1.10/mojo/apps/logit/models/__init__.py +1 -0
  75. django_nativemojo-0.1.10/mojo/apps/logit/models/log.py +57 -0
  76. django_nativemojo-0.1.10/mojo/apps/logit/rest.py +9 -0
  77. django_nativemojo-0.1.10/mojo/apps/metrics/README.md +79 -0
  78. django_nativemojo-0.1.10/mojo/apps/metrics/__init__.py +12 -0
  79. django_nativemojo-0.1.10/mojo/apps/metrics/redis_metrics.py +331 -0
  80. django_nativemojo-0.1.10/mojo/apps/metrics/rest/__init__.py +1 -0
  81. django_nativemojo-0.1.10/mojo/apps/metrics/rest/base.py +152 -0
  82. django_nativemojo-0.1.10/mojo/apps/metrics/rest/db.py +0 -0
  83. django_nativemojo-0.1.10/mojo/apps/metrics/utils.py +227 -0
  84. django_nativemojo-0.1.10/mojo/apps/notify/README.md +91 -0
  85. django_nativemojo-0.1.10/mojo/apps/notify/README_NOTIFICATIONS.md +566 -0
  86. django_nativemojo-0.1.10/mojo/apps/notify/__init__.py +0 -0
  87. django_nativemojo-0.1.10/mojo/apps/notify/admin.py +52 -0
  88. django_nativemojo-0.1.10/mojo/apps/notify/handlers/__init__.py +0 -0
  89. django_nativemojo-0.1.10/mojo/apps/notify/handlers/example_handlers.py +516 -0
  90. django_nativemojo-0.1.10/mojo/apps/notify/handlers/ses/__init__.py +25 -0
  91. django_nativemojo-0.1.10/mojo/apps/notify/handlers/ses/bounce.py +0 -0
  92. django_nativemojo-0.1.10/mojo/apps/notify/handlers/ses/complaint.py +25 -0
  93. django_nativemojo-0.1.10/mojo/apps/notify/handlers/ses/message.py +86 -0
  94. django_nativemojo-0.1.10/mojo/apps/notify/management/__init__.py +0 -0
  95. django_nativemojo-0.1.10/mojo/apps/notify/management/commands/__init__.py +1 -0
  96. django_nativemojo-0.1.10/mojo/apps/notify/management/commands/process_notifications.py +370 -0
  97. django_nativemojo-0.1.10/mojo/apps/notify/mod +0 -0
  98. django_nativemojo-0.1.10/mojo/apps/notify/models/__init__.py +12 -0
  99. django_nativemojo-0.1.10/mojo/apps/notify/models/account.py +128 -0
  100. django_nativemojo-0.1.10/mojo/apps/notify/models/attachment.py +24 -0
  101. django_nativemojo-0.1.10/mojo/apps/notify/models/bounce.py +68 -0
  102. django_nativemojo-0.1.10/mojo/apps/notify/models/complaint.py +40 -0
  103. django_nativemojo-0.1.10/mojo/apps/notify/models/inbox.py +113 -0
  104. django_nativemojo-0.1.10/mojo/apps/notify/models/inbox_message.py +173 -0
  105. django_nativemojo-0.1.10/mojo/apps/notify/models/outbox.py +129 -0
  106. django_nativemojo-0.1.10/mojo/apps/notify/models/outbox_message.py +288 -0
  107. django_nativemojo-0.1.10/mojo/apps/notify/models/template.py +30 -0
  108. django_nativemojo-0.1.10/mojo/apps/notify/providers/__init__.py +0 -0
  109. django_nativemojo-0.1.10/mojo/apps/notify/providers/aws.py +73 -0
  110. django_nativemojo-0.1.10/mojo/apps/notify/rest/__init__.py +0 -0
  111. django_nativemojo-0.1.10/mojo/apps/notify/rest/ses.py +0 -0
  112. django_nativemojo-0.1.10/mojo/apps/notify/utils/__init__.py +2 -0
  113. django_nativemojo-0.1.10/mojo/apps/notify/utils/notifications.py +404 -0
  114. django_nativemojo-0.1.10/mojo/apps/notify/utils/parsing.py +202 -0
  115. django_nativemojo-0.1.10/mojo/apps/notify/utils/render.py +144 -0
  116. django_nativemojo-0.1.10/mojo/apps/tasks/README.md +118 -0
  117. django_nativemojo-0.1.10/mojo/apps/tasks/__init__.py +11 -0
  118. django_nativemojo-0.1.10/mojo/apps/tasks/manager.py +489 -0
  119. django_nativemojo-0.1.10/mojo/apps/tasks/rest/__init__.py +2 -0
  120. django_nativemojo-0.1.10/mojo/apps/tasks/rest/hooks.py +0 -0
  121. django_nativemojo-0.1.10/mojo/apps/tasks/rest/tasks.py +62 -0
  122. django_nativemojo-0.1.10/mojo/apps/tasks/runner.py +174 -0
  123. django_nativemojo-0.1.10/mojo/apps/tasks/tq_handlers.py +14 -0
  124. django_nativemojo-0.1.10/mojo/decorators/__init__.py +3 -0
  125. django_nativemojo-0.1.10/mojo/decorators/auth.py +25 -0
  126. django_nativemojo-0.1.10/mojo/decorators/cron.py +31 -0
  127. django_nativemojo-0.1.10/mojo/decorators/http.py +132 -0
  128. django_nativemojo-0.1.10/mojo/decorators/validate.py +14 -0
  129. django_nativemojo-0.1.10/mojo/errors.py +88 -0
  130. django_nativemojo-0.1.10/mojo/helpers/__init__.py +0 -0
  131. django_nativemojo-0.1.10/mojo/helpers/aws/__init__.py +0 -0
  132. django_nativemojo-0.1.10/mojo/helpers/aws/client.py +8 -0
  133. django_nativemojo-0.1.10/mojo/helpers/aws/s3.py +268 -0
  134. django_nativemojo-0.1.10/mojo/helpers/aws/setup_email.py +0 -0
  135. django_nativemojo-0.1.10/mojo/helpers/cron.py +79 -0
  136. django_nativemojo-0.1.10/mojo/helpers/crypto/__init__.py +4 -0
  137. django_nativemojo-0.1.10/mojo/helpers/crypto/aes.py +60 -0
  138. django_nativemojo-0.1.10/mojo/helpers/crypto/hash.py +59 -0
  139. django_nativemojo-0.1.10/mojo/helpers/crypto/privpub/__init__.py +1 -0
  140. django_nativemojo-0.1.10/mojo/helpers/crypto/privpub/hybrid.py +97 -0
  141. django_nativemojo-0.1.10/mojo/helpers/crypto/privpub/rsa.py +104 -0
  142. django_nativemojo-0.1.10/mojo/helpers/crypto/sign.py +36 -0
  143. django_nativemojo-0.1.10/mojo/helpers/crypto/too.l.py +25 -0
  144. django_nativemojo-0.1.10/mojo/helpers/crypto/utils.py +26 -0
  145. django_nativemojo-0.1.10/mojo/helpers/daemon.py +94 -0
  146. django_nativemojo-0.1.10/mojo/helpers/dates.py +69 -0
  147. django_nativemojo-0.1.10/mojo/helpers/dns/__init__.py +0 -0
  148. django_nativemojo-0.1.10/mojo/helpers/dns/godaddy.py +62 -0
  149. django_nativemojo-0.1.10/mojo/helpers/filetypes.py +128 -0
  150. django_nativemojo-0.1.10/mojo/helpers/logit.py +310 -0
  151. django_nativemojo-0.1.10/mojo/helpers/modules.py +95 -0
  152. django_nativemojo-0.1.10/mojo/helpers/paths.py +63 -0
  153. django_nativemojo-0.1.10/mojo/helpers/redis.py +10 -0
  154. django_nativemojo-0.1.10/mojo/helpers/request.py +89 -0
  155. django_nativemojo-0.1.10/mojo/helpers/request_parser.py +269 -0
  156. django_nativemojo-0.1.10/mojo/helpers/response.py +14 -0
  157. django_nativemojo-0.1.10/mojo/helpers/settings.py +146 -0
  158. django_nativemojo-0.1.10/mojo/helpers/sysinfo.py +140 -0
  159. django_nativemojo-0.1.10/mojo/helpers/ua.py +0 -0
  160. django_nativemojo-0.1.10/mojo/middleware/__init__.py +0 -0
  161. django_nativemojo-0.1.10/mojo/middleware/auth.py +26 -0
  162. django_nativemojo-0.1.10/mojo/middleware/logging.py +55 -0
  163. django_nativemojo-0.1.10/mojo/middleware/mojo.py +21 -0
  164. django_nativemojo-0.1.10/mojo/migrations/0001_initial.py +32 -0
  165. django_nativemojo-0.1.10/mojo/migrations/__init__.py +0 -0
  166. django_nativemojo-0.1.10/mojo/models/__init__.py +2 -0
  167. django_nativemojo-0.1.10/mojo/models/meta.py +262 -0
  168. django_nativemojo-0.1.10/mojo/models/rest.py +538 -0
  169. django_nativemojo-0.1.10/mojo/models/secrets.py +59 -0
  170. django_nativemojo-0.1.10/mojo/rest/__init__.py +1 -0
  171. django_nativemojo-0.1.10/mojo/rest/info.py +26 -0
  172. django_nativemojo-0.1.10/mojo/serializers/__init__.py +0 -0
  173. django_nativemojo-0.1.10/mojo/serializers/models.py +165 -0
  174. django_nativemojo-0.1.10/mojo/serializers/openapi.py +188 -0
  175. django_nativemojo-0.1.10/mojo/urls.py +38 -0
  176. django_nativemojo-0.1.10/mojo/ws4redis/README.md +174 -0
  177. django_nativemojo-0.1.10/mojo/ws4redis/__init__.py +2 -0
  178. django_nativemojo-0.1.10/mojo/ws4redis/client.py +283 -0
  179. django_nativemojo-0.1.10/mojo/ws4redis/connection.py +327 -0
  180. django_nativemojo-0.1.10/mojo/ws4redis/exceptions.py +32 -0
  181. django_nativemojo-0.1.10/mojo/ws4redis/redis.py +183 -0
  182. django_nativemojo-0.1.10/mojo/ws4redis/servers/__init__.py +0 -0
  183. django_nativemojo-0.1.10/mojo/ws4redis/servers/base.py +86 -0
  184. django_nativemojo-0.1.10/mojo/ws4redis/servers/django.py +171 -0
  185. django_nativemojo-0.1.10/mojo/ws4redis/servers/uwsgi.py +63 -0
  186. django_nativemojo-0.1.10/mojo/ws4redis/settings.py +45 -0
  187. django_nativemojo-0.1.10/mojo/ws4redis/utf8validator.py +128 -0
  188. django_nativemojo-0.1.10/mojo/ws4redis/websocket.py +403 -0
  189. django_nativemojo-0.1.10/pyproject.toml +34 -0
  190. django_nativemojo-0.1.10/testit/__init__.py +0 -0
  191. django_nativemojo-0.1.10/testit/client.py +147 -0
  192. django_nativemojo-0.1.10/testit/faker.py +20 -0
  193. django_nativemojo-0.1.10/testit/helpers.py +198 -0
  194. django_nativemojo-0.1.10/testit/runner.py +262 -0
@@ -0,0 +1,19 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ Copyright [2025] Native Mojo
8
+
9
+ Licensed under the Apache License, Version 2.0 (the "License");
10
+ you may not use this file except in compliance with the License.
11
+ You may obtain a copy of the License at
12
+
13
+ http://www.apache.org/licenses/LICENSE-2.0
14
+
15
+ Unless required by applicable law or agreed to in writing, software
16
+ distributed under the License is distributed on an "AS IS" BASIS,
17
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ See the License for the specific language governing permissions and
19
+ limitations under the License.
@@ -0,0 +1,8 @@
1
+ Native Mojo Framework
2
+ Copyright 2025 Native Mojo
3
+
4
+ This product includes software developed by Native Mojo.
5
+ Licensed under the Apache License, Version 2.0 (the "License").
6
+
7
+ You may obtain a copy of the License at:
8
+ http://www.apache.org/licenses/LICENSE-2.0
@@ -0,0 +1,96 @@
1
+ Metadata-Version: 2.3
2
+ Name: django-nativemojo
3
+ Version: 0.1.10
4
+ Summary: A REST framework for DJANGO with some extra apps that make it easy to provide a secure robust graph like RESIT API.
5
+ License: MIT
6
+ Author: MOJO Dev Team
7
+ Author-email: gotmojo@nativemojo.com
8
+ Requires-Python: >=3.9,<4.0
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.9
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Requires-Dist: django (>=4.2.18,<6.0.0)
17
+ Requires-Dist: django-cors-headers (>=4.7.0,<5.0.0)
18
+ Requires-Dist: faker (>=35.2.0,<36.0.0)
19
+ Requires-Dist: gevent (>=25.5.1,<26.0.0)
20
+ Requires-Dist: pycryptodome (>=3.21.0,<4.0.0)
21
+ Requires-Dist: pyjwt (>=2.10.1,<3.0.0)
22
+ Requires-Dist: pyobjict (>=2.0.2,<4.0.0)
23
+ Requires-Dist: pytz (>=2025.1,<2026.0)
24
+ Requires-Dist: redis (>=3.5.3,<6.0.0)
25
+ Requires-Dist: requests (>=2.32.3,<3.0.0)
26
+ Requires-Dist: ua-parser (>=1.0.1,<2.0.0)
27
+ Requires-Dist: ujson (>=5.10.0,<6.0.0)
28
+ Description-Content-Type: text/markdown
29
+
30
+ # Django-MOJO Documentation
31
+
32
+ Django-MOJO is a streamlined set of Django applications and a lightweight REST framework designed to simplify user authentication, authorization, and efficient API testing. This documentation provides descriptions and examples to help you get started quickly.
33
+
34
+ ## Why Django-MOJO?
35
+
36
+ We built Django-MOJO to address the complexity and overhead of existing REST frameworks. Many frameworks are feature-heavy, making them cumbersome for projects that require simplicity, speed, and robust security.
37
+
38
+ ## Key Differentiators
39
+
40
+ - **Lightweight Framework:** Django-MOJO is minimalistic, providing an easy way to add REST APIs to your Django models without unnecessary complexity.
41
+ - **Built-in Security:** Security is integral to Django-MOJO. We offer an alternative to Django's built-in permissions system, automatically protecting your REST APIs and data.
42
+ - **Robust Object-Level Permission System:** Unlike Django's native model-level permissions, Django-MOJO provides a simple yet robust permission system at the object level. This allows fine-grained control, enabling permissions to be applied to individual objects and extended to both user and group levels.
43
+ - **Effortless Integration:** Adding REST endpoints to your models is straightforward, enabling rapid development without compromising security or performance.
44
+
45
+ With Django-MOJO, you get a simple, efficient framework with powerful security features designed for developers who value speed and control.
46
+
47
+ ## Table of Contents
48
+
49
+ 1. [Overview](#overview)
50
+ 2. [Installation](#installation)
51
+ 3. [MOJO.Auth - Authentication and Authorization](#mojo-auth)
52
+ - [JWT Authentication Middleware](#jwt-authentication)
53
+ - [Models](#models)
54
+ - [REST API](#mojo-auth-rest-api)
55
+ 4. [MOJO - REST Framework](#mojo)
56
+ - [URL Decorators](#url-decorators)
57
+ - [GraphSerializer](#graphserializer)
58
+ 5. [Testit - Testing Suite](#testit)
59
+ - [Writing Tests](#writing-tests)
60
+ - [Running Tests](#running-tests)
61
+ 6. [Taskit - Task Runner](#taskit)
62
+ 7. [Utilities](#utilities)
63
+ 8. [Contributing](#contributing)
64
+ 9. [License](#license)
65
+
66
+ ## Overview
67
+
68
+ Django-MOJO is a collection of Django-based applications focused on authentication, task management, and testing. These tools are built to enhance development efficiency by providing utilities for common requirements such as user management, token-based authentication, and automated testing.
69
+
70
+ ## Installation
71
+
72
+ ```bash
73
+ pip install django-nativemojo
74
+ ```
75
+
76
+ ## Detailed Documentation
77
+
78
+ For detailed information about each module and its usage, refer to the documentation within the `docs` folder:
79
+
80
+ - [MOJO Auth Documentation](docs/auth.md): Authentication and authorization management with JWT support.
81
+ - [MOJO REST Documentation](docs/rest.md): Provides RESTful API capabilities for Django models.
82
+ - [MOJO Testing Documentation](docs/testit.md): Offers tools and utilities for testing Django applications.
83
+ - [MOJO Tasks Documentation](docs/tasks.md): Handles task management and processing with Redis.
84
+ - [MOJO Decorators Documentation](docs/decorators.md): Describes decorators to enhance Django views with HTTP routing, validation, etc.
85
+ - [Helpers Documentation](docs/helpers.md): Lists various helper utilities for common tasks.
86
+ - [MOJO Metrics Documentation](docs/metrics.md): Details on recording and retrieving metrics using Redis.
87
+ - [Cron Scheduler Documentation](docs/cron.md): Explains task scheduling using a cron syntax.
88
+
89
+ ## Contributing
90
+
91
+ We welcome contributions! Please create an issue or submit a pull request on the GitHub repository.
92
+
93
+ ## License
94
+
95
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
96
+
@@ -0,0 +1,66 @@
1
+ # Django-MOJO Documentation
2
+
3
+ Django-MOJO is a streamlined set of Django applications and a lightweight REST framework designed to simplify user authentication, authorization, and efficient API testing. This documentation provides descriptions and examples to help you get started quickly.
4
+
5
+ ## Why Django-MOJO?
6
+
7
+ We built Django-MOJO to address the complexity and overhead of existing REST frameworks. Many frameworks are feature-heavy, making them cumbersome for projects that require simplicity, speed, and robust security.
8
+
9
+ ## Key Differentiators
10
+
11
+ - **Lightweight Framework:** Django-MOJO is minimalistic, providing an easy way to add REST APIs to your Django models without unnecessary complexity.
12
+ - **Built-in Security:** Security is integral to Django-MOJO. We offer an alternative to Django's built-in permissions system, automatically protecting your REST APIs and data.
13
+ - **Robust Object-Level Permission System:** Unlike Django's native model-level permissions, Django-MOJO provides a simple yet robust permission system at the object level. This allows fine-grained control, enabling permissions to be applied to individual objects and extended to both user and group levels.
14
+ - **Effortless Integration:** Adding REST endpoints to your models is straightforward, enabling rapid development without compromising security or performance.
15
+
16
+ With Django-MOJO, you get a simple, efficient framework with powerful security features designed for developers who value speed and control.
17
+
18
+ ## Table of Contents
19
+
20
+ 1. [Overview](#overview)
21
+ 2. [Installation](#installation)
22
+ 3. [MOJO.Auth - Authentication and Authorization](#mojo-auth)
23
+ - [JWT Authentication Middleware](#jwt-authentication)
24
+ - [Models](#models)
25
+ - [REST API](#mojo-auth-rest-api)
26
+ 4. [MOJO - REST Framework](#mojo)
27
+ - [URL Decorators](#url-decorators)
28
+ - [GraphSerializer](#graphserializer)
29
+ 5. [Testit - Testing Suite](#testit)
30
+ - [Writing Tests](#writing-tests)
31
+ - [Running Tests](#running-tests)
32
+ 6. [Taskit - Task Runner](#taskit)
33
+ 7. [Utilities](#utilities)
34
+ 8. [Contributing](#contributing)
35
+ 9. [License](#license)
36
+
37
+ ## Overview
38
+
39
+ Django-MOJO is a collection of Django-based applications focused on authentication, task management, and testing. These tools are built to enhance development efficiency by providing utilities for common requirements such as user management, token-based authentication, and automated testing.
40
+
41
+ ## Installation
42
+
43
+ ```bash
44
+ pip install django-nativemojo
45
+ ```
46
+
47
+ ## Detailed Documentation
48
+
49
+ For detailed information about each module and its usage, refer to the documentation within the `docs` folder:
50
+
51
+ - [MOJO Auth Documentation](docs/auth.md): Authentication and authorization management with JWT support.
52
+ - [MOJO REST Documentation](docs/rest.md): Provides RESTful API capabilities for Django models.
53
+ - [MOJO Testing Documentation](docs/testit.md): Offers tools and utilities for testing Django applications.
54
+ - [MOJO Tasks Documentation](docs/tasks.md): Handles task management and processing with Redis.
55
+ - [MOJO Decorators Documentation](docs/decorators.md): Describes decorators to enhance Django views with HTTP routing, validation, etc.
56
+ - [Helpers Documentation](docs/helpers.md): Lists various helper utilities for common tasks.
57
+ - [MOJO Metrics Documentation](docs/metrics.md): Details on recording and retrieving metrics using Redis.
58
+ - [Cron Scheduler Documentation](docs/cron.md): Explains task scheduling using a cron syntax.
59
+
60
+ ## Contributing
61
+
62
+ We welcome contributions! Please create an issue or submit a pull request on the GitHub repository.
63
+
64
+ ## License
65
+
66
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,3 @@
1
+ __version__ = "0.1.10"
2
+
3
+ from mojo.helpers.response import JsonResponse
@@ -0,0 +1 @@
1
+ default_app_config = 'account.apps.AppConfig'
@@ -0,0 +1,91 @@
1
+ from django.contrib import admin
2
+ from django.utils.translation import gettext_lazy as _
3
+ from .models import User, Group, GroupMember
4
+
5
+
6
+ class UserAdmin(admin.ModelAdmin):
7
+ """Custom Admin for the User model"""
8
+
9
+ # Fields displayed in the User list in Django Admin
10
+ list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff', 'is_active', 'last_login', 'id')
11
+ list_filter = ('is_staff', 'is_active')
12
+
13
+ # Fields displayed when viewing/editing a user
14
+ fieldsets = (
15
+ (None, {'fields': ('username', 'password')}),
16
+ (_('Personal Info'), {'fields': ('first_name', 'last_name', 'email', 'phone_number', 'display_name')}),
17
+ (_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser')}),
18
+ (_('Important Dates'), {'fields': ('last_login', 'date_joined', 'last_activity')}),
19
+ (_('Metadata'), {'fields': ('permissions', 'metadata')}),
20
+ )
21
+
22
+ # Fields displayed when adding a new user
23
+ add_fieldsets = (
24
+ (None, {
25
+ 'classes': ('wide',),
26
+ 'fields': ('username', 'email', 'password'),
27
+ }),
28
+ )
29
+
30
+ # Searchable fields in the admin panel
31
+ search_fields = ('username', 'email', 'first_name', 'last_name')
32
+ ordering = ('username',)
33
+
34
+ # Read-only fields for security
35
+ readonly_fields = ('last_login', 'date_joined', 'last_activity')
36
+
37
+ admin.site.register(User, UserAdmin)
38
+
39
+
40
+
41
+ class GroupAdmin(admin.ModelAdmin):
42
+ """Custom Admin for the Group model"""
43
+
44
+ # Fields displayed in the Group list in Django Admin
45
+ list_display = ('name', 'uuid', 'kind', 'is_active', 'created', 'modified', 'parent', 'id')
46
+ list_filter = ('is_active', 'kind')
47
+
48
+ # Searchable fields
49
+ search_fields = ('name', 'uuid', 'kind')
50
+
51
+ # Read-only fields for security
52
+ readonly_fields = ('created', 'modified')
53
+
54
+ # Fields displayed when viewing/editing a group
55
+ fieldsets = (
56
+ (None, {'fields': ('name', 'uuid', 'kind', 'is_active', 'parent')}),
57
+ ('Metadata', {'fields': ('metadata',)}),
58
+ ('Timestamps', {'fields': ('created', 'modified')}),
59
+ )
60
+
61
+ autocomplete_fields = ('parent',)
62
+
63
+
64
+ admin.site.register(Group, GroupAdmin)
65
+
66
+
67
+
68
+ class GroupMemberAdmin(admin.ModelAdmin):
69
+ """Custom Admin for the GroupMember model"""
70
+
71
+ # Fields displayed in the GroupMember list in Django Admin
72
+ list_display = ('user', 'group', 'is_active', 'created', 'modified', 'id')
73
+ list_filter = ('is_active', 'group')
74
+
75
+ # Searchable fields
76
+ search_fields = ('user__username', 'user__email', 'group__name')
77
+
78
+ # Read-only fields for security
79
+ readonly_fields = ('created', 'modified')
80
+
81
+ # Fields displayed when viewing/editing a group member
82
+ fieldsets = (
83
+ (None, {'fields': ('user', 'group', 'is_active')}),
84
+ ('Permissions', {'fields': ('permissions',)}),
85
+ ('Metadata', {'fields': ('metadata',)}),
86
+ ('Timestamps', {'fields': ('created', 'modified')}),
87
+ )
88
+
89
+ autocomplete_fields = ('group', 'user', )
90
+
91
+ admin.site.register(GroupMember, GroupMemberAdmin)
@@ -0,0 +1,16 @@
1
+ from django.apps import AppConfig as BaseAppConfig
2
+
3
+ class AppConfig(BaseAppConfig):
4
+ default_auto_field = 'django.db.models.BigAutoField'
5
+ name = 'mojo.apps.account'
6
+
7
+ def ready(self):
8
+ from mojo.helpers.settings import settings
9
+ if settings.is_app_installed("django.contrib.admin"):
10
+ self.unregister_apps()
11
+
12
+ def unregister_apps(self):
13
+ from django.contrib import admin
14
+ from django.contrib.auth.models import Group
15
+ for model in [Group]:
16
+ admin.site.unregister(model)
@@ -0,0 +1,77 @@
1
+ # Generated by Django 4.2.21 on 2025-05-29 21:29
2
+
3
+ from django.conf import settings
4
+ from django.db import migrations, models
5
+ import django.db.models.deletion
6
+ import mojo.models.rest
7
+ import uuid
8
+
9
+
10
+ class Migration(migrations.Migration):
11
+
12
+ initial = True
13
+
14
+ dependencies = [
15
+ ]
16
+
17
+ operations = [
18
+ migrations.CreateModel(
19
+ name='User',
20
+ fields=[
21
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
22
+ ('password', models.CharField(max_length=128, verbose_name='password')),
23
+ ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
24
+ ('created', models.DateTimeField(auto_now_add=True)),
25
+ ('modified', models.DateTimeField(auto_now_add=True)),
26
+ ('last_activity', models.DateTimeField(db_index=True, default=None, null=True)),
27
+ ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False)),
28
+ ('username', models.TextField(unique=True)),
29
+ ('email', models.EmailField(max_length=254, unique=True)),
30
+ ('phone_number', models.CharField(blank=True, default=None, max_length=32, null=True)),
31
+ ('display_name', models.CharField(blank=True, default=None, max_length=80, null=True)),
32
+ ('auth_key', models.TextField(default=None, null=True)),
33
+ ('onetime_code', models.TextField(default=None, null=True)),
34
+ ('permissions', models.JSONField(blank=True, default=dict)),
35
+ ('metadata', models.JSONField(blank=True, default=dict)),
36
+ ('first_name', models.CharField(default='', max_length=80)),
37
+ ('last_name', models.CharField(default='', max_length=80)),
38
+ ('is_active', models.BooleanField(default=True)),
39
+ ('is_staff', models.BooleanField(default=False)),
40
+ ('is_superuser', models.BooleanField(default=False)),
41
+ ('date_joined', models.DateTimeField(auto_now_add=True)),
42
+ ],
43
+ options={
44
+ 'abstract': False,
45
+ },
46
+ bases=(models.Model, mojo.models.rest.MojoModel),
47
+ ),
48
+ migrations.CreateModel(
49
+ name='Group',
50
+ fields=[
51
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
52
+ ('created', models.DateTimeField(auto_now_add=True)),
53
+ ('modified', models.DateTimeField(auto_now=True, db_index=True)),
54
+ ('name', models.CharField(max_length=200)),
55
+ ('uuid', models.CharField(db_index=True, default=None, max_length=200, null=True)),
56
+ ('is_active', models.BooleanField(db_index=True, default=True)),
57
+ ('kind', models.CharField(db_index=True, default='group', max_length=80)),
58
+ ('metadata', models.JSONField(blank=True, default=dict)),
59
+ ('parent', models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='groups', to='account.group')),
60
+ ],
61
+ bases=(models.Model, mojo.models.rest.MojoModel),
62
+ ),
63
+ migrations.CreateModel(
64
+ name='GroupMember',
65
+ fields=[
66
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
67
+ ('created', models.DateTimeField(auto_now_add=True)),
68
+ ('modified', models.DateTimeField(auto_now=True, db_index=True)),
69
+ ('is_active', models.BooleanField(db_index=True, default=True)),
70
+ ('permissions', models.JSONField(blank=True, default=dict)),
71
+ ('metadata', models.JSONField(blank=True, default=dict)),
72
+ ('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='members', to='account.group')),
73
+ ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='members', to=settings.AUTH_USER_MODEL)),
74
+ ],
75
+ bases=(models.Model, mojo.models.rest.MojoModel),
76
+ ),
77
+ ]
@@ -0,0 +1,23 @@
1
+ # Generated by Django 4.2.21 on 2025-06-04 02:13
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('account', '0001_initial'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AddField(
14
+ model_name='user',
15
+ name='is_email_verified',
16
+ field=models.BooleanField(default=False),
17
+ ),
18
+ migrations.AddField(
19
+ model_name='user',
20
+ name='is_phone_verified',
21
+ field=models.BooleanField(default=False),
22
+ ),
23
+ ]
@@ -0,0 +1,23 @@
1
+ # Generated by Django 4.2.21 on 2025-06-04 19:19
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('account', '0002_user_is_email_verified_user_is_phone_verified'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AddField(
14
+ model_name='group',
15
+ name='mojo_secrets',
16
+ field=models.TextField(blank=True, default=None, null=True),
17
+ ),
18
+ migrations.AddField(
19
+ model_name='user',
20
+ name='mojo_secrets',
21
+ field=models.TextField(blank=True, default=None, null=True),
22
+ ),
23
+ ]
@@ -0,0 +1,3 @@
1
+ from .group import Group
2
+ from .user import User
3
+ from .member import GroupMember
@@ -0,0 +1,98 @@
1
+ from django.db import models
2
+ from mojo.models import MojoModel, MojoSecrets
3
+ from mojo.helpers import dates
4
+
5
+
6
+
7
+ class Group(MojoSecrets, MojoModel):
8
+ """
9
+ Group model.
10
+ """
11
+ created = models.DateTimeField(auto_now_add=True, editable=False)
12
+ modified = models.DateTimeField(auto_now=True, db_index=True)
13
+
14
+ name = models.CharField(max_length=200)
15
+ uuid = models.CharField(max_length=200, null=True, default=None, db_index=True)
16
+ is_active = models.BooleanField(default=True, db_index=True)
17
+ kind = models.CharField(max_length=80, default="group", db_index=True)
18
+
19
+ parent = models.ForeignKey("account.Group", null=True, related_name="groups",
20
+ default=None, on_delete=models.CASCADE)
21
+
22
+ # JSON-based metadata field
23
+ metadata = models.JSONField(default=dict, blank=True)
24
+
25
+ class RestMeta:
26
+ SEARCH_FIELDS = ["name"]
27
+ VIEW_PERMS = ["view_groups", "manage_groups"]
28
+ SAVE_PERMS = ["manage_groups"]
29
+ LIST_DEFAULT_FILTERS = {
30
+ "is_active": True
31
+ }
32
+ GRAPHS = {
33
+ "basic": {
34
+ "fields": [
35
+ 'id',
36
+ 'name',
37
+ 'created',
38
+ 'modified',
39
+ 'is_active',
40
+ 'kind',
41
+ ]
42
+ },
43
+ "default": {
44
+ "fields": [
45
+ 'id',
46
+ 'name',
47
+ 'created',
48
+ 'modified',
49
+ 'is_active',
50
+ 'kind',
51
+ 'parent',
52
+ 'metadata'
53
+ ]
54
+ },
55
+ "graphs": {
56
+ "parent": "basic"
57
+ }
58
+ }
59
+
60
+ @property
61
+ def timezone(self):
62
+ return self.metadata.get("timezone", "America/Los_Angeles")
63
+
64
+ def get_local_day(self, dt_utc=None):
65
+ return dates.get_local_day(self.timezone, dt_utc)
66
+
67
+ def get_local_time(self, dt_utc):
68
+ return dates.get_local_time(self.timezone, dt_utc)
69
+
70
+ def __str__(self):
71
+ return self.name
72
+
73
+ def has_permission(self, user):
74
+ from mojo.account.models.member import GroupMember
75
+ return GroupMember.objects.filter(user=user).last()
76
+
77
+ def member_has_permission(self, user, perms, check_user=True):
78
+ if check_user and user.has_permission(perms):
79
+ return True
80
+ ms = self.has_permission(user)
81
+ if ms is not None:
82
+ return ms.has_permission(perms)
83
+ return False
84
+
85
+ def get_metadata(self):
86
+ # converts our local metadata into an objict
87
+ self.metadata = self.jsonfield_as_objict("metadata")
88
+ return self.metadata
89
+
90
+ def get_member_for_user(self, user):
91
+ return self.members.filter(user=user).last()
92
+
93
+ @classmethod
94
+ def on_rest_handle_list(cls, request):
95
+ if cls.rest_check_permission(request, "VIEW_PERMS"):
96
+ return cls.on_rest_list(request)
97
+ group_ids = request.user.members.values_list('group__id', flat=True)
98
+ return cls.on_rest_list(request, cls.objects.filter(id__in=group_ids))
@@ -0,0 +1,95 @@
1
+ from django.db import models
2
+ from mojo.models import MojoModel
3
+ from mojo import errors as merrors
4
+ from mojo.helpers.settings import settings
5
+
6
+ MEMBER_PERMS_PROTECTION = settings.get("MEMBER_PERMS_PROTECTION", {})
7
+
8
+
9
+ class GroupMember(models.Model, MojoModel):
10
+ """
11
+ A member of a group
12
+ """
13
+ created = models.DateTimeField(auto_now_add=True, editable=False)
14
+ modified = models.DateTimeField(auto_now=True, db_index=True)
15
+ user = models.ForeignKey(
16
+ "account.User",related_name="members",
17
+ on_delete=models.CASCADE)
18
+ group = models.ForeignKey(
19
+ "account.Group", related_name="members",
20
+ on_delete=models.CASCADE)
21
+ is_active = models.BooleanField(default=True, db_index=True)
22
+ # JSON-based permissions field
23
+ permissions = models.JSONField(default=dict, blank=True)
24
+ # JSON-based metadata field
25
+ metadata = models.JSONField(default=dict, blank=True)
26
+
27
+ class RestMeta:
28
+ VIEW_PERMS = ["view_groups", "manage_groups"]
29
+ SAVE_PERMS = ["manage_groups"]
30
+ LIST_DEFAULT_FILTERS = {
31
+ "is_active": True
32
+ }
33
+ GRAPHS = {
34
+ "default": {
35
+ "fields": [
36
+ 'id',
37
+ 'name',
38
+ 'created',
39
+ 'modified',
40
+ 'is_active',
41
+ 'permissions',
42
+ 'metadata'
43
+ ],
44
+ "graphs": {
45
+ "user": "basic",
46
+ "group": "basic"
47
+ }
48
+ }
49
+ }
50
+
51
+ def __str__(self):
52
+ return f"{self.user.username}@{self.group.name}"
53
+
54
+ def can_change_permission(self, perm, value, request):
55
+ if request.user.has_permission(["manage_groups", "manage_users"]):
56
+ return True
57
+ req_member = self.group.get_member_for_user(request.user)
58
+ if req_member is not None:
59
+ if perm in MEMBER_PERMS_PROTECTION:
60
+ return req_member.has_permission(MEMBER_PERMS_PROTECTION[perm])
61
+ return req_member.has_permission(["manage_group", "manage_members"])
62
+ return False
63
+
64
+ def set_permissions(self, value, request):
65
+ if not isinstance(value, dict):
66
+ return
67
+ for perm, perm_value in value.items():
68
+ if not self.can_change_permission(perm, perm_value, request):
69
+ raise merrors.PermissionDeniedException()
70
+ if bool(perm_value):
71
+ self.add_permission(perm)
72
+ else:
73
+ self.remove_permission(perm)
74
+
75
+ def has_permission(self, perm_key):
76
+ """Check if user has a specific permission in JSON field."""
77
+ if isinstance(perm_key, list):
78
+ for pk in perm_key:
79
+ if self.has_permission(pk):
80
+ return True
81
+ return False
82
+ if perm_key == "all":
83
+ return True
84
+ return self.permissions.get(perm_key, False)
85
+
86
+ def add_permission(self, perm_key, value=True):
87
+ """Dynamically add a permission."""
88
+ self.permissions[perm_key] = value
89
+ self.save()
90
+
91
+ def remove_permission(self, perm_key):
92
+ """Remove a permission."""
93
+ if perm_key in self.permissions:
94
+ del self.permissions[perm_key]
95
+ self.save()
@@ -0,0 +1,18 @@
1
+ from django.db import models
2
+
3
+ class Passkey(models.Model):
4
+ user = models.ForeignKey(
5
+ "account.User",related_name="members",
6
+ on_delete=models.CASCADE)
7
+ token = models.TextField()
8
+
9
+ credential_id = models.CharField(max_length=255, unique=True)
10
+ rp_id = models.CharField(max_length=255, null=False, db_index=True)
11
+ is_enabled = models.BooleanField(default=True, db_index=True)
12
+
13
+ created = models.DateTimeField(auto_now_add=True)
14
+ modified = models.DateTimeField(auto_now=True)
15
+ last_used = models.DateTimeField(null=True, blank=True, default=None)
16
+
17
+ def __str__(self):
18
+ return f"{self.user.username} - {self.credential_id} - {self.rp_id}"