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.
- django_nativemojo-0.1.10/LICENSE +19 -0
- django_nativemojo-0.1.10/NOTICE +8 -0
- django_nativemojo-0.1.10/PKG-INFO +96 -0
- django_nativemojo-0.1.10/README.md +66 -0
- django_nativemojo-0.1.10/mojo/__init__.py +3 -0
- django_nativemojo-0.1.10/mojo/apps/account/__init__.py +1 -0
- django_nativemojo-0.1.10/mojo/apps/account/admin.py +91 -0
- django_nativemojo-0.1.10/mojo/apps/account/apps.py +16 -0
- django_nativemojo-0.1.10/mojo/apps/account/migrations/0001_initial.py +77 -0
- django_nativemojo-0.1.10/mojo/apps/account/migrations/0002_user_is_email_verified_user_is_phone_verified.py +23 -0
- django_nativemojo-0.1.10/mojo/apps/account/migrations/0003_group_mojo_secrets_user_mojo_secrets.py +23 -0
- django_nativemojo-0.1.10/mojo/apps/account/migrations/__init__.py +0 -0
- django_nativemojo-0.1.10/mojo/apps/account/models/__init__.py +3 -0
- django_nativemojo-0.1.10/mojo/apps/account/models/group.py +98 -0
- django_nativemojo-0.1.10/mojo/apps/account/models/member.py +95 -0
- django_nativemojo-0.1.10/mojo/apps/account/models/pkey.py +18 -0
- django_nativemojo-0.1.10/mojo/apps/account/models/user.py +211 -0
- django_nativemojo-0.1.10/mojo/apps/account/rest/__init__.py +3 -0
- django_nativemojo-0.1.10/mojo/apps/account/rest/group.py +25 -0
- django_nativemojo-0.1.10/mojo/apps/account/rest/user.py +47 -0
- django_nativemojo-0.1.10/mojo/apps/account/utils/__init__.py +0 -0
- django_nativemojo-0.1.10/mojo/apps/account/utils/jwtoken.py +72 -0
- django_nativemojo-0.1.10/mojo/apps/account/utils/passkeys.py +54 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/README.md +549 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/__init__.py +0 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/apps.py +15 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/backends/__init__.py +117 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/backends/base.py +319 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/backends/filesystem.py +397 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/backends/s3.py +398 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/examples/configurations.py +378 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/examples/usage_example.py +665 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/management/__init__.py +1 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/management/commands/__init__.py +1 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/management/commands/cleanup_expired_uploads.py +222 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/models/__init__.py +7 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/models/file.py +292 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/models/manager.py +227 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/models/render.py +0 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/rest/__init__ +0 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/rest/__init__.py +23 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/rest/fileman.py +13 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/rest/upload.py +92 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/utils/__init__.py +19 -0
- django_nativemojo-0.1.10/mojo/apps/fileman/utils/upload.py +616 -0
- django_nativemojo-0.1.10/mojo/apps/incident/__init__.py +1 -0
- django_nativemojo-0.1.10/mojo/apps/incident/handlers/__init__.py +3 -0
- django_nativemojo-0.1.10/mojo/apps/incident/handlers/event_handlers.py +142 -0
- django_nativemojo-0.1.10/mojo/apps/incident/migrations/0001_initial.py +83 -0
- django_nativemojo-0.1.10/mojo/apps/incident/migrations/0002_rename_bundle_ruleset_bundle_minutes_event_hostname_and_more.py +44 -0
- django_nativemojo-0.1.10/mojo/apps/incident/migrations/0003_alter_event_model_id.py +18 -0
- django_nativemojo-0.1.10/mojo/apps/incident/migrations/0004_alter_incident_model_id.py +18 -0
- django_nativemojo-0.1.10/mojo/apps/incident/migrations/__init__.py +0 -0
- django_nativemojo-0.1.10/mojo/apps/incident/models/__init__.py +3 -0
- django_nativemojo-0.1.10/mojo/apps/incident/models/event.py +135 -0
- django_nativemojo-0.1.10/mojo/apps/incident/models/incident.py +33 -0
- django_nativemojo-0.1.10/mojo/apps/incident/models/rule.py +247 -0
- django_nativemojo-0.1.10/mojo/apps/incident/parsers/__init__.py +0 -0
- django_nativemojo-0.1.10/mojo/apps/incident/parsers/ossec/__init__.py +1 -0
- django_nativemojo-0.1.10/mojo/apps/incident/parsers/ossec/core.py +82 -0
- django_nativemojo-0.1.10/mojo/apps/incident/parsers/ossec/parsed.py +23 -0
- django_nativemojo-0.1.10/mojo/apps/incident/parsers/ossec/rules.py +124 -0
- django_nativemojo-0.1.10/mojo/apps/incident/parsers/ossec/utils.py +169 -0
- django_nativemojo-0.1.10/mojo/apps/incident/reporter.py +42 -0
- django_nativemojo-0.1.10/mojo/apps/incident/rest/__init__.py +2 -0
- django_nativemojo-0.1.10/mojo/apps/incident/rest/event.py +23 -0
- django_nativemojo-0.1.10/mojo/apps/incident/rest/ossec.py +22 -0
- django_nativemojo-0.1.10/mojo/apps/logit/__init__.py +0 -0
- django_nativemojo-0.1.10/mojo/apps/logit/admin.py +37 -0
- django_nativemojo-0.1.10/mojo/apps/logit/migrations/0001_initial.py +32 -0
- django_nativemojo-0.1.10/mojo/apps/logit/migrations/0002_log_duid_log_payload_log_username.py +28 -0
- django_nativemojo-0.1.10/mojo/apps/logit/migrations/0003_log_level.py +18 -0
- django_nativemojo-0.1.10/mojo/apps/logit/migrations/__init__.py +0 -0
- django_nativemojo-0.1.10/mojo/apps/logit/models/__init__.py +1 -0
- django_nativemojo-0.1.10/mojo/apps/logit/models/log.py +57 -0
- django_nativemojo-0.1.10/mojo/apps/logit/rest.py +9 -0
- django_nativemojo-0.1.10/mojo/apps/metrics/README.md +79 -0
- django_nativemojo-0.1.10/mojo/apps/metrics/__init__.py +12 -0
- django_nativemojo-0.1.10/mojo/apps/metrics/redis_metrics.py +331 -0
- django_nativemojo-0.1.10/mojo/apps/metrics/rest/__init__.py +1 -0
- django_nativemojo-0.1.10/mojo/apps/metrics/rest/base.py +152 -0
- django_nativemojo-0.1.10/mojo/apps/metrics/rest/db.py +0 -0
- django_nativemojo-0.1.10/mojo/apps/metrics/utils.py +227 -0
- django_nativemojo-0.1.10/mojo/apps/notify/README.md +91 -0
- django_nativemojo-0.1.10/mojo/apps/notify/README_NOTIFICATIONS.md +566 -0
- django_nativemojo-0.1.10/mojo/apps/notify/__init__.py +0 -0
- django_nativemojo-0.1.10/mojo/apps/notify/admin.py +52 -0
- django_nativemojo-0.1.10/mojo/apps/notify/handlers/__init__.py +0 -0
- django_nativemojo-0.1.10/mojo/apps/notify/handlers/example_handlers.py +516 -0
- django_nativemojo-0.1.10/mojo/apps/notify/handlers/ses/__init__.py +25 -0
- django_nativemojo-0.1.10/mojo/apps/notify/handlers/ses/bounce.py +0 -0
- django_nativemojo-0.1.10/mojo/apps/notify/handlers/ses/complaint.py +25 -0
- django_nativemojo-0.1.10/mojo/apps/notify/handlers/ses/message.py +86 -0
- django_nativemojo-0.1.10/mojo/apps/notify/management/__init__.py +0 -0
- django_nativemojo-0.1.10/mojo/apps/notify/management/commands/__init__.py +1 -0
- django_nativemojo-0.1.10/mojo/apps/notify/management/commands/process_notifications.py +370 -0
- django_nativemojo-0.1.10/mojo/apps/notify/mod +0 -0
- django_nativemojo-0.1.10/mojo/apps/notify/models/__init__.py +12 -0
- django_nativemojo-0.1.10/mojo/apps/notify/models/account.py +128 -0
- django_nativemojo-0.1.10/mojo/apps/notify/models/attachment.py +24 -0
- django_nativemojo-0.1.10/mojo/apps/notify/models/bounce.py +68 -0
- django_nativemojo-0.1.10/mojo/apps/notify/models/complaint.py +40 -0
- django_nativemojo-0.1.10/mojo/apps/notify/models/inbox.py +113 -0
- django_nativemojo-0.1.10/mojo/apps/notify/models/inbox_message.py +173 -0
- django_nativemojo-0.1.10/mojo/apps/notify/models/outbox.py +129 -0
- django_nativemojo-0.1.10/mojo/apps/notify/models/outbox_message.py +288 -0
- django_nativemojo-0.1.10/mojo/apps/notify/models/template.py +30 -0
- django_nativemojo-0.1.10/mojo/apps/notify/providers/__init__.py +0 -0
- django_nativemojo-0.1.10/mojo/apps/notify/providers/aws.py +73 -0
- django_nativemojo-0.1.10/mojo/apps/notify/rest/__init__.py +0 -0
- django_nativemojo-0.1.10/mojo/apps/notify/rest/ses.py +0 -0
- django_nativemojo-0.1.10/mojo/apps/notify/utils/__init__.py +2 -0
- django_nativemojo-0.1.10/mojo/apps/notify/utils/notifications.py +404 -0
- django_nativemojo-0.1.10/mojo/apps/notify/utils/parsing.py +202 -0
- django_nativemojo-0.1.10/mojo/apps/notify/utils/render.py +144 -0
- django_nativemojo-0.1.10/mojo/apps/tasks/README.md +118 -0
- django_nativemojo-0.1.10/mojo/apps/tasks/__init__.py +11 -0
- django_nativemojo-0.1.10/mojo/apps/tasks/manager.py +489 -0
- django_nativemojo-0.1.10/mojo/apps/tasks/rest/__init__.py +2 -0
- django_nativemojo-0.1.10/mojo/apps/tasks/rest/hooks.py +0 -0
- django_nativemojo-0.1.10/mojo/apps/tasks/rest/tasks.py +62 -0
- django_nativemojo-0.1.10/mojo/apps/tasks/runner.py +174 -0
- django_nativemojo-0.1.10/mojo/apps/tasks/tq_handlers.py +14 -0
- django_nativemojo-0.1.10/mojo/decorators/__init__.py +3 -0
- django_nativemojo-0.1.10/mojo/decorators/auth.py +25 -0
- django_nativemojo-0.1.10/mojo/decorators/cron.py +31 -0
- django_nativemojo-0.1.10/mojo/decorators/http.py +132 -0
- django_nativemojo-0.1.10/mojo/decorators/validate.py +14 -0
- django_nativemojo-0.1.10/mojo/errors.py +88 -0
- django_nativemojo-0.1.10/mojo/helpers/__init__.py +0 -0
- django_nativemojo-0.1.10/mojo/helpers/aws/__init__.py +0 -0
- django_nativemojo-0.1.10/mojo/helpers/aws/client.py +8 -0
- django_nativemojo-0.1.10/mojo/helpers/aws/s3.py +268 -0
- django_nativemojo-0.1.10/mojo/helpers/aws/setup_email.py +0 -0
- django_nativemojo-0.1.10/mojo/helpers/cron.py +79 -0
- django_nativemojo-0.1.10/mojo/helpers/crypto/__init__.py +4 -0
- django_nativemojo-0.1.10/mojo/helpers/crypto/aes.py +60 -0
- django_nativemojo-0.1.10/mojo/helpers/crypto/hash.py +59 -0
- django_nativemojo-0.1.10/mojo/helpers/crypto/privpub/__init__.py +1 -0
- django_nativemojo-0.1.10/mojo/helpers/crypto/privpub/hybrid.py +97 -0
- django_nativemojo-0.1.10/mojo/helpers/crypto/privpub/rsa.py +104 -0
- django_nativemojo-0.1.10/mojo/helpers/crypto/sign.py +36 -0
- django_nativemojo-0.1.10/mojo/helpers/crypto/too.l.py +25 -0
- django_nativemojo-0.1.10/mojo/helpers/crypto/utils.py +26 -0
- django_nativemojo-0.1.10/mojo/helpers/daemon.py +94 -0
- django_nativemojo-0.1.10/mojo/helpers/dates.py +69 -0
- django_nativemojo-0.1.10/mojo/helpers/dns/__init__.py +0 -0
- django_nativemojo-0.1.10/mojo/helpers/dns/godaddy.py +62 -0
- django_nativemojo-0.1.10/mojo/helpers/filetypes.py +128 -0
- django_nativemojo-0.1.10/mojo/helpers/logit.py +310 -0
- django_nativemojo-0.1.10/mojo/helpers/modules.py +95 -0
- django_nativemojo-0.1.10/mojo/helpers/paths.py +63 -0
- django_nativemojo-0.1.10/mojo/helpers/redis.py +10 -0
- django_nativemojo-0.1.10/mojo/helpers/request.py +89 -0
- django_nativemojo-0.1.10/mojo/helpers/request_parser.py +269 -0
- django_nativemojo-0.1.10/mojo/helpers/response.py +14 -0
- django_nativemojo-0.1.10/mojo/helpers/settings.py +146 -0
- django_nativemojo-0.1.10/mojo/helpers/sysinfo.py +140 -0
- django_nativemojo-0.1.10/mojo/helpers/ua.py +0 -0
- django_nativemojo-0.1.10/mojo/middleware/__init__.py +0 -0
- django_nativemojo-0.1.10/mojo/middleware/auth.py +26 -0
- django_nativemojo-0.1.10/mojo/middleware/logging.py +55 -0
- django_nativemojo-0.1.10/mojo/middleware/mojo.py +21 -0
- django_nativemojo-0.1.10/mojo/migrations/0001_initial.py +32 -0
- django_nativemojo-0.1.10/mojo/migrations/__init__.py +0 -0
- django_nativemojo-0.1.10/mojo/models/__init__.py +2 -0
- django_nativemojo-0.1.10/mojo/models/meta.py +262 -0
- django_nativemojo-0.1.10/mojo/models/rest.py +538 -0
- django_nativemojo-0.1.10/mojo/models/secrets.py +59 -0
- django_nativemojo-0.1.10/mojo/rest/__init__.py +1 -0
- django_nativemojo-0.1.10/mojo/rest/info.py +26 -0
- django_nativemojo-0.1.10/mojo/serializers/__init__.py +0 -0
- django_nativemojo-0.1.10/mojo/serializers/models.py +165 -0
- django_nativemojo-0.1.10/mojo/serializers/openapi.py +188 -0
- django_nativemojo-0.1.10/mojo/urls.py +38 -0
- django_nativemojo-0.1.10/mojo/ws4redis/README.md +174 -0
- django_nativemojo-0.1.10/mojo/ws4redis/__init__.py +2 -0
- django_nativemojo-0.1.10/mojo/ws4redis/client.py +283 -0
- django_nativemojo-0.1.10/mojo/ws4redis/connection.py +327 -0
- django_nativemojo-0.1.10/mojo/ws4redis/exceptions.py +32 -0
- django_nativemojo-0.1.10/mojo/ws4redis/redis.py +183 -0
- django_nativemojo-0.1.10/mojo/ws4redis/servers/__init__.py +0 -0
- django_nativemojo-0.1.10/mojo/ws4redis/servers/base.py +86 -0
- django_nativemojo-0.1.10/mojo/ws4redis/servers/django.py +171 -0
- django_nativemojo-0.1.10/mojo/ws4redis/servers/uwsgi.py +63 -0
- django_nativemojo-0.1.10/mojo/ws4redis/settings.py +45 -0
- django_nativemojo-0.1.10/mojo/ws4redis/utf8validator.py +128 -0
- django_nativemojo-0.1.10/mojo/ws4redis/websocket.py +403 -0
- django_nativemojo-0.1.10/pyproject.toml +34 -0
- django_nativemojo-0.1.10/testit/__init__.py +0 -0
- django_nativemojo-0.1.10/testit/client.py +147 -0
- django_nativemojo-0.1.10/testit/faker.py +20 -0
- django_nativemojo-0.1.10/testit/helpers.py +198 -0
- 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 @@
|
|
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
|
+
]
|
django_nativemojo-0.1.10/mojo/apps/account/migrations/0003_group_mojo_secrets_user_mojo_secrets.py
ADDED
@@ -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
|
+
]
|
File without changes
|
@@ -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}"
|