django-nativemojo 0.1.15__py3-none-any.whl → 0.1.16__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.
- {django_nativemojo-0.1.15.dist-info → django_nativemojo-0.1.16.dist-info}/METADATA +3 -1
- django_nativemojo-0.1.16.dist-info/RECORD +302 -0
- mojo/__init__.py +1 -1
- mojo/apps/account/management/commands/serializer_admin.py +121 -1
- mojo/apps/account/migrations/0006_add_device_tracking_models.py +72 -0
- mojo/apps/account/migrations/0007_delete_userdevicelocation.py +16 -0
- mojo/apps/account/migrations/0008_userdevicelocation.py +33 -0
- mojo/apps/account/migrations/0009_geolocatedip_subnet.py +18 -0
- mojo/apps/account/migrations/0010_group_avatar.py +20 -0
- mojo/apps/account/migrations/0011_user_org_registereddevice_pushconfig_and_more.py +118 -0
- mojo/apps/account/migrations/0012_remove_pushconfig_apns_key_file_and_more.py +21 -0
- mojo/apps/account/migrations/0013_pushconfig_test_mode_alter_pushconfig_apns_enabled_and_more.py +28 -0
- mojo/apps/account/migrations/0014_notificationdelivery_data_payload_and_more.py +48 -0
- mojo/apps/account/models/__init__.py +2 -0
- mojo/apps/account/models/device.py +281 -0
- mojo/apps/account/models/group.py +294 -8
- mojo/apps/account/models/member.py +14 -1
- mojo/apps/account/models/push/__init__.py +4 -0
- mojo/apps/account/models/push/config.py +112 -0
- mojo/apps/account/models/push/delivery.py +93 -0
- mojo/apps/account/models/push/device.py +66 -0
- mojo/apps/account/models/push/template.py +99 -0
- mojo/apps/account/models/user.py +190 -17
- mojo/apps/account/rest/__init__.py +2 -0
- mojo/apps/account/rest/device.py +39 -0
- mojo/apps/account/rest/group.py +8 -0
- mojo/apps/account/rest/push.py +187 -0
- mojo/apps/account/rest/user.py +95 -5
- mojo/apps/account/services/__init__.py +1 -0
- mojo/apps/account/services/push.py +363 -0
- mojo/apps/aws/migrations/0001_initial.py +206 -0
- mojo/apps/aws/migrations/0002_emaildomain_can_recv_emaildomain_can_send_and_more.py +28 -0
- mojo/apps/aws/migrations/0003_mailbox_is_domain_default_mailbox_is_system_default_and_more.py +31 -0
- mojo/apps/aws/migrations/0004_s3bucket.py +39 -0
- mojo/apps/aws/migrations/0005_alter_emaildomain_region_delete_s3bucket.py +21 -0
- mojo/apps/aws/models/__init__.py +19 -0
- mojo/apps/aws/models/email_attachment.py +99 -0
- mojo/apps/aws/models/email_domain.py +218 -0
- mojo/apps/aws/models/email_template.py +132 -0
- mojo/apps/aws/models/incoming_email.py +197 -0
- mojo/apps/aws/models/mailbox.py +288 -0
- mojo/apps/aws/models/sent_message.py +175 -0
- mojo/apps/aws/rest/__init__.py +6 -0
- mojo/apps/aws/rest/email.py +33 -0
- mojo/apps/aws/rest/email_ops.py +183 -0
- mojo/apps/aws/rest/messages.py +32 -0
- mojo/apps/aws/rest/send.py +101 -0
- mojo/apps/aws/rest/sns.py +403 -0
- mojo/apps/aws/rest/templates.py +19 -0
- mojo/apps/aws/services/__init__.py +32 -0
- mojo/apps/aws/services/email.py +390 -0
- mojo/apps/aws/services/email_ops.py +548 -0
- mojo/apps/docit/__init__.py +6 -0
- mojo/apps/docit/markdown_plugins/syntax_highlight.py +25 -0
- mojo/apps/docit/markdown_plugins/toc.py +12 -0
- mojo/apps/docit/migrations/0001_initial.py +113 -0
- mojo/apps/docit/migrations/0002_alter_book_modified_by_alter_page_modified_by.py +26 -0
- mojo/apps/docit/migrations/0003_alter_book_group.py +20 -0
- mojo/apps/docit/models/__init__.py +17 -0
- mojo/apps/docit/models/asset.py +231 -0
- mojo/apps/docit/models/book.py +227 -0
- mojo/apps/docit/models/page.py +319 -0
- mojo/apps/docit/models/page_revision.py +203 -0
- mojo/apps/docit/rest/__init__.py +10 -0
- mojo/apps/docit/rest/asset.py +17 -0
- mojo/apps/docit/rest/book.py +22 -0
- mojo/apps/docit/rest/page.py +22 -0
- mojo/apps/docit/rest/page_revision.py +17 -0
- mojo/apps/docit/services/__init__.py +11 -0
- mojo/apps/docit/services/docit.py +315 -0
- mojo/apps/docit/services/markdown.py +44 -0
- mojo/apps/fileman/backends/s3.py +209 -0
- mojo/apps/fileman/models/file.py +45 -9
- mojo/apps/fileman/models/manager.py +269 -3
- mojo/apps/incident/migrations/0007_event_uid.py +18 -0
- mojo/apps/incident/migrations/0008_ticket_ticketnote.py +55 -0
- mojo/apps/incident/migrations/0009_incident_status.py +18 -0
- mojo/apps/incident/migrations/0010_event_country_code.py +18 -0
- mojo/apps/incident/migrations/0011_incident_country_code.py +18 -0
- mojo/apps/incident/migrations/0012_alter_incident_status.py +18 -0
- mojo/apps/incident/models/__init__.py +1 -0
- mojo/apps/incident/models/event.py +35 -0
- mojo/apps/incident/models/incident.py +2 -0
- mojo/apps/incident/models/ticket.py +62 -0
- mojo/apps/incident/reporter.py +21 -3
- mojo/apps/incident/rest/__init__.py +1 -0
- mojo/apps/incident/rest/ticket.py +43 -0
- mojo/apps/jobs/__init__.py +489 -0
- mojo/apps/jobs/adapters.py +24 -0
- mojo/apps/jobs/cli.py +616 -0
- mojo/apps/jobs/daemon.py +370 -0
- mojo/apps/jobs/examples/sample_jobs.py +376 -0
- mojo/apps/jobs/examples/webhook_examples.py +203 -0
- mojo/apps/jobs/handlers/__init__.py +5 -0
- mojo/apps/jobs/handlers/webhook.py +317 -0
- mojo/apps/jobs/job_engine.py +734 -0
- mojo/apps/jobs/keys.py +203 -0
- mojo/apps/jobs/local_queue.py +363 -0
- mojo/apps/jobs/management/__init__.py +3 -0
- mojo/apps/jobs/management/commands/__init__.py +3 -0
- mojo/apps/jobs/manager.py +1327 -0
- mojo/apps/jobs/migrations/0001_initial.py +97 -0
- mojo/apps/jobs/migrations/0002_alter_job_max_retries_joblog.py +39 -0
- mojo/apps/jobs/models/__init__.py +6 -0
- mojo/apps/jobs/models/job.py +441 -0
- mojo/apps/jobs/rest/__init__.py +2 -0
- mojo/apps/jobs/rest/control.py +466 -0
- mojo/apps/jobs/rest/jobs.py +421 -0
- mojo/apps/jobs/scheduler.py +571 -0
- mojo/apps/jobs/services/__init__.py +6 -0
- mojo/apps/jobs/services/job_actions.py +465 -0
- mojo/apps/jobs/settings.py +209 -0
- mojo/apps/logit/models/log.py +3 -0
- mojo/apps/metrics/__init__.py +8 -1
- mojo/apps/metrics/redis_metrics.py +198 -0
- mojo/apps/metrics/rest/__init__.py +3 -0
- mojo/apps/metrics/rest/categories.py +266 -0
- mojo/apps/metrics/rest/helpers.py +48 -0
- mojo/apps/metrics/rest/permissions.py +99 -0
- mojo/apps/metrics/rest/values.py +277 -0
- mojo/apps/metrics/utils.py +17 -0
- mojo/decorators/http.py +40 -1
- mojo/helpers/aws/__init__.py +11 -7
- mojo/helpers/aws/inbound_email.py +309 -0
- mojo/helpers/aws/kms.py +413 -0
- mojo/helpers/aws/ses_domain.py +959 -0
- mojo/helpers/crypto/__init__.py +1 -1
- mojo/helpers/crypto/utils.py +15 -0
- mojo/helpers/location/__init__.py +2 -0
- mojo/helpers/location/countries.py +262 -0
- mojo/helpers/location/geolocation.py +196 -0
- mojo/helpers/logit.py +37 -0
- mojo/helpers/redis/__init__.py +2 -0
- mojo/helpers/redis/adapter.py +606 -0
- mojo/helpers/redis/client.py +48 -0
- mojo/helpers/redis/pool.py +225 -0
- mojo/helpers/request.py +8 -0
- mojo/helpers/response.py +8 -0
- mojo/middleware/auth.py +1 -1
- mojo/middleware/cors.py +40 -0
- mojo/middleware/logging.py +131 -12
- mojo/middleware/mojo.py +5 -0
- mojo/models/rest.py +271 -57
- mojo/models/secrets.py +86 -0
- mojo/serializers/__init__.py +16 -10
- mojo/serializers/core/__init__.py +90 -0
- mojo/serializers/core/cache/__init__.py +121 -0
- mojo/serializers/core/cache/backends.py +518 -0
- mojo/serializers/core/cache/base.py +102 -0
- mojo/serializers/core/cache/disabled.py +181 -0
- mojo/serializers/core/cache/memory.py +287 -0
- mojo/serializers/core/cache/redis.py +533 -0
- mojo/serializers/core/cache/utils.py +454 -0
- mojo/serializers/{manager.py → core/manager.py} +53 -4
- mojo/serializers/core/serializer.py +475 -0
- mojo/serializers/{advanced/formats → formats}/csv.py +116 -139
- mojo/serializers/suggested_improvements.md +388 -0
- testit/client.py +1 -1
- testit/helpers.py +14 -0
- testit/runner.py +23 -6
- django_nativemojo-0.1.15.dist-info/RECORD +0 -234
- mojo/apps/notify/README.md +0 -91
- mojo/apps/notify/README_NOTIFICATIONS.md +0 -566
- mojo/apps/notify/admin.py +0 -52
- mojo/apps/notify/handlers/example_handlers.py +0 -516
- mojo/apps/notify/handlers/ses/__init__.py +0 -25
- mojo/apps/notify/handlers/ses/complaint.py +0 -25
- mojo/apps/notify/handlers/ses/message.py +0 -86
- mojo/apps/notify/management/commands/__init__.py +0 -1
- mojo/apps/notify/management/commands/process_notifications.py +0 -370
- mojo/apps/notify/mod +0 -0
- mojo/apps/notify/models/__init__.py +0 -12
- mojo/apps/notify/models/account.py +0 -128
- mojo/apps/notify/models/attachment.py +0 -24
- mojo/apps/notify/models/bounce.py +0 -68
- mojo/apps/notify/models/complaint.py +0 -40
- mojo/apps/notify/models/inbox.py +0 -113
- mojo/apps/notify/models/inbox_message.py +0 -173
- mojo/apps/notify/models/outbox.py +0 -129
- mojo/apps/notify/models/outbox_message.py +0 -288
- mojo/apps/notify/models/template.py +0 -30
- mojo/apps/notify/providers/aws.py +0 -73
- mojo/apps/notify/rest/ses.py +0 -0
- mojo/apps/notify/utils/__init__.py +0 -2
- mojo/apps/notify/utils/notifications.py +0 -404
- mojo/apps/notify/utils/parsing.py +0 -202
- mojo/apps/notify/utils/render.py +0 -144
- mojo/apps/tasks/README.md +0 -118
- mojo/apps/tasks/__init__.py +0 -44
- mojo/apps/tasks/manager.py +0 -644
- mojo/apps/tasks/rest/__init__.py +0 -2
- mojo/apps/tasks/rest/hooks.py +0 -0
- mojo/apps/tasks/rest/tasks.py +0 -76
- mojo/apps/tasks/runner.py +0 -439
- mojo/apps/tasks/task.py +0 -99
- mojo/apps/tasks/tq_handlers.py +0 -132
- mojo/helpers/crypto/__pycache__/hash.cpython-310.pyc +0 -0
- mojo/helpers/crypto/__pycache__/sign.cpython-310.pyc +0 -0
- mojo/helpers/crypto/__pycache__/utils.cpython-310.pyc +0 -0
- mojo/helpers/redis.py +0 -10
- mojo/models/meta.py +0 -262
- mojo/serializers/advanced/README.md +0 -363
- mojo/serializers/advanced/__init__.py +0 -247
- mojo/serializers/advanced/formats/__init__.py +0 -28
- mojo/serializers/advanced/formats/excel.py +0 -516
- mojo/serializers/advanced/formats/json.py +0 -239
- mojo/serializers/advanced/formats/response.py +0 -485
- mojo/serializers/advanced/serializer.py +0 -568
- mojo/serializers/optimized.py +0 -618
- {django_nativemojo-0.1.15.dist-info → django_nativemojo-0.1.16.dist-info}/LICENSE +0 -0
- {django_nativemojo-0.1.15.dist-info → django_nativemojo-0.1.16.dist-info}/NOTICE +0 -0
- {django_nativemojo-0.1.15.dist-info → django_nativemojo-0.1.16.dist-info}/WHEEL +0 -0
- /mojo/apps/{notify → aws/migrations}/__init__.py +0 -0
- /mojo/apps/{notify/handlers → docit/markdown_plugins}/__init__.py +0 -0
- /mojo/apps/{notify/management → docit/migrations}/__init__.py +0 -0
- /mojo/apps/{notify/providers → jobs/examples}/__init__.py +0 -0
- /mojo/apps/{notify/rest → jobs/migrations}/__init__.py +0 -0
- /mojo/{serializers → rest}/openapi.py +0 -0
- /mojo/serializers/{settings_example.py → examples/settings.py} +0 -0
- /mojo/{apps/notify/handlers/ses/bounce.py → serializers/formats/__init__.py} +0 -0
- /mojo/serializers/{advanced/formats → formats}/localizers.py +0 -0
@@ -0,0 +1,277 @@
|
|
1
|
+
from mojo import decorators as md
|
2
|
+
from mojo.apps import metrics
|
3
|
+
from mojo.helpers.response import JsonResponse
|
4
|
+
import mojo.errors
|
5
|
+
import datetime
|
6
|
+
from .helpers import check_view_permissions, check_write_permissions
|
7
|
+
|
8
|
+
# Documentation for time-series metrics endpoints
|
9
|
+
SERIES_GET_DOCS = {
|
10
|
+
"summary": "Get time-series values at a point in time",
|
11
|
+
"description": "Retrieves time-series metric values for multiple slugs at a specific datetime and granularity.",
|
12
|
+
"parameters": [
|
13
|
+
{
|
14
|
+
"name": "slugs",
|
15
|
+
"in": "query",
|
16
|
+
"required": True,
|
17
|
+
"schema": {"type": "string"},
|
18
|
+
"description": "Comma-separated list of slugs to fetch values for (e.g., 'user_activity_day,page_views')."
|
19
|
+
},
|
20
|
+
{
|
21
|
+
"name": "when",
|
22
|
+
"in": "query",
|
23
|
+
"required": True,
|
24
|
+
"schema": {"type": "string", "format": "date-time"},
|
25
|
+
"description": "The specific date/datetime to fetch values for."
|
26
|
+
},
|
27
|
+
{
|
28
|
+
"name": "granularity",
|
29
|
+
"in": "query",
|
30
|
+
"schema": {"type": "string", "default": "hours"},
|
31
|
+
"description": "Granularity of the data (e.g., 'hours', 'days', 'months', 'years')."
|
32
|
+
},
|
33
|
+
{
|
34
|
+
"name": "account",
|
35
|
+
"in": "query",
|
36
|
+
"schema": {"type": "string", "default": "public"},
|
37
|
+
"description": "Account identifier (e.g., 'public', 'global', or 'group_<id>')."
|
38
|
+
}
|
39
|
+
],
|
40
|
+
"responses": {
|
41
|
+
"200": {
|
42
|
+
"description": "Successful response with metric values.",
|
43
|
+
"content": {
|
44
|
+
"application/json": {
|
45
|
+
"example": {
|
46
|
+
"response": {
|
47
|
+
"data": {
|
48
|
+
"user_activity_day": 22,
|
49
|
+
"page_views": 156
|
50
|
+
},
|
51
|
+
"slugs": ["user_activity_day", "page_views"],
|
52
|
+
"when": "2025-08-01T00:00:00",
|
53
|
+
"granularity": "days",
|
54
|
+
"account": "public",
|
55
|
+
"status": True
|
56
|
+
},
|
57
|
+
"status_code": 200
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
SERIES_POST_DOCS = {
|
66
|
+
"summary": "Get time-series values at a point in time (POST)",
|
67
|
+
"description": "Retrieves time-series metric values for multiple slugs at a specific datetime and granularity using POST method.",
|
68
|
+
"parameters": [
|
69
|
+
{
|
70
|
+
"name": "slugs",
|
71
|
+
"in": "body",
|
72
|
+
"required": True,
|
73
|
+
"schema": {"type": "string"},
|
74
|
+
"description": "Comma-separated list of slugs to fetch values for (e.g., 'user_activity_day,page_views')."
|
75
|
+
},
|
76
|
+
{
|
77
|
+
"name": "when",
|
78
|
+
"in": "body",
|
79
|
+
"required": True,
|
80
|
+
"schema": {"type": "string", "format": "date-time"},
|
81
|
+
"description": "The specific date/datetime to fetch values for."
|
82
|
+
},
|
83
|
+
{
|
84
|
+
"name": "granularity",
|
85
|
+
"in": "body",
|
86
|
+
"schema": {"type": "string", "default": "hours"},
|
87
|
+
"description": "Granularity of the data (e.g., 'hours', 'days', 'months', 'years')."
|
88
|
+
},
|
89
|
+
{
|
90
|
+
"name": "account",
|
91
|
+
"in": "body",
|
92
|
+
"schema": {"type": "string", "default": "public"},
|
93
|
+
"description": "Account identifier (e.g., 'public', 'global', or 'group_<id>')."
|
94
|
+
}
|
95
|
+
]
|
96
|
+
}
|
97
|
+
|
98
|
+
# Documentation for simple value storage endpoints
|
99
|
+
SET_VALUE_DOCS = {
|
100
|
+
"summary": "Set simple global values",
|
101
|
+
"description": "Sets simple key-value pairs for global storage (not time-series).",
|
102
|
+
"parameters": [
|
103
|
+
{
|
104
|
+
"name": "slug",
|
105
|
+
"in": "body",
|
106
|
+
"required": True,
|
107
|
+
"schema": {"type": "string"},
|
108
|
+
"description": "The key identifier for the value to set."
|
109
|
+
},
|
110
|
+
{
|
111
|
+
"name": "value",
|
112
|
+
"in": "body",
|
113
|
+
"required": True,
|
114
|
+
"schema": {"type": "string"},
|
115
|
+
"description": "The value to store."
|
116
|
+
},
|
117
|
+
{
|
118
|
+
"name": "account",
|
119
|
+
"in": "body",
|
120
|
+
"schema": {"type": "string", "default": "public"},
|
121
|
+
"description": "Account identifier (e.g., 'public', 'global', or 'group_<id>')."
|
122
|
+
}
|
123
|
+
],
|
124
|
+
"responses": {
|
125
|
+
"200": {
|
126
|
+
"description": "Successful value storage.",
|
127
|
+
"content": {
|
128
|
+
"application/json": {
|
129
|
+
"example": {
|
130
|
+
"response": {
|
131
|
+
"slug": "max_users",
|
132
|
+
"value": "1000",
|
133
|
+
"account": "public",
|
134
|
+
"status": True
|
135
|
+
},
|
136
|
+
"status_code": 200
|
137
|
+
}
|
138
|
+
}
|
139
|
+
}
|
140
|
+
}
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
VALUE_GET_DOCS = {
|
145
|
+
"summary": "Get simple global values",
|
146
|
+
"description": "Retrieves simple key-value pairs from global storage (not time-series). Supports multiple slugs.",
|
147
|
+
"parameters": [
|
148
|
+
{
|
149
|
+
"name": "slugs",
|
150
|
+
"in": "query",
|
151
|
+
"required": True,
|
152
|
+
"schema": {"type": "string"},
|
153
|
+
"description": "Comma-separated list of slugs to fetch values for (e.g., 'max_users,maintenance_mode')."
|
154
|
+
},
|
155
|
+
{
|
156
|
+
"name": "account",
|
157
|
+
"in": "query",
|
158
|
+
"schema": {"type": "string", "default": "public"},
|
159
|
+
"description": "Account identifier (e.g., 'public', 'global', or 'group_<id>')."
|
160
|
+
},
|
161
|
+
{
|
162
|
+
"name": "default",
|
163
|
+
"in": "query",
|
164
|
+
"schema": {"type": "string"},
|
165
|
+
"description": "Default value to return for missing keys."
|
166
|
+
}
|
167
|
+
],
|
168
|
+
"responses": {
|
169
|
+
"200": {
|
170
|
+
"description": "Successful response with values.",
|
171
|
+
"content": {
|
172
|
+
"application/json": {
|
173
|
+
"example": {
|
174
|
+
"response": {
|
175
|
+
"data": {
|
176
|
+
"max_users": "1000",
|
177
|
+
"maintenance_mode": "false"
|
178
|
+
},
|
179
|
+
"slugs": ["max_users", "maintenance_mode"],
|
180
|
+
"account": "public",
|
181
|
+
"status": True
|
182
|
+
},
|
183
|
+
"status_code": 200
|
184
|
+
}
|
185
|
+
}
|
186
|
+
}
|
187
|
+
}
|
188
|
+
}
|
189
|
+
}
|
190
|
+
|
191
|
+
|
192
|
+
# Time-series metrics endpoints
|
193
|
+
@md.GET('series', docs=SERIES_GET_DOCS)
|
194
|
+
@md.requires_params("slugs")
|
195
|
+
def on_metrics_series(request):
|
196
|
+
"""
|
197
|
+
Get time-series values for multiple slugs at a single point in time.
|
198
|
+
"""
|
199
|
+
when = request.DATA.get_typed("when")
|
200
|
+
account = request.DATA.get("account", "public")
|
201
|
+
granularity = request.DATA.get("granularity", "hours")
|
202
|
+
slugs = request.DATA.get("slugs")
|
203
|
+
|
204
|
+
check_view_permissions(request, account)
|
205
|
+
|
206
|
+
# Fetch the values using our new method
|
207
|
+
result = metrics.fetch_values(slugs, when, granularity, account=account)
|
208
|
+
result['status'] = True
|
209
|
+
|
210
|
+
return JsonResponse(result)
|
211
|
+
|
212
|
+
|
213
|
+
@md.POST('series', docs=SERIES_POST_DOCS)
|
214
|
+
@md.requires_params("slugs")
|
215
|
+
def on_metrics_series_post(request):
|
216
|
+
"""
|
217
|
+
POST version of the series endpoint - same functionality as GET.
|
218
|
+
"""
|
219
|
+
return on_metrics_series(request)
|
220
|
+
|
221
|
+
|
222
|
+
# Simple value storage endpoints
|
223
|
+
@md.POST('value/set', docs=SET_VALUE_DOCS)
|
224
|
+
@md.requires_params("slug", "value")
|
225
|
+
def on_set_value(request):
|
226
|
+
"""
|
227
|
+
Set a simple global value (not time-series).
|
228
|
+
"""
|
229
|
+
slug = request.DATA.get("slug")
|
230
|
+
value = request.DATA.get("value")
|
231
|
+
account = request.DATA.get("account", "public")
|
232
|
+
|
233
|
+
check_write_permissions(request, account)
|
234
|
+
|
235
|
+
metrics.set_value(slug, value, account=account)
|
236
|
+
|
237
|
+
return JsonResponse({
|
238
|
+
"slug": slug,
|
239
|
+
"value": value,
|
240
|
+
"account": account,
|
241
|
+
"status": True
|
242
|
+
})
|
243
|
+
|
244
|
+
|
245
|
+
@md.GET('value/get', docs=VALUE_GET_DOCS)
|
246
|
+
@md.requires_params("slugs")
|
247
|
+
def on_get_value(request):
|
248
|
+
"""
|
249
|
+
Get simple global values for multiple slugs (not time-series).
|
250
|
+
"""
|
251
|
+
slugs = request.DATA.get("slugs")
|
252
|
+
account = request.DATA.get("account", "public")
|
253
|
+
default = request.DATA.get("default")
|
254
|
+
|
255
|
+
check_view_permissions(request, account)
|
256
|
+
|
257
|
+
# Handle comma-separated string input
|
258
|
+
if isinstance(slugs, str):
|
259
|
+
if ',' in slugs:
|
260
|
+
slugs_list = [s.strip() for s in slugs.split(',')]
|
261
|
+
else:
|
262
|
+
slugs_list = [slugs]
|
263
|
+
else:
|
264
|
+
slugs_list = slugs
|
265
|
+
|
266
|
+
# Fetch values for all slugs
|
267
|
+
data = {}
|
268
|
+
for slug in slugs_list:
|
269
|
+
value = metrics.get_value(slug, account=account, default=default)
|
270
|
+
data[slug] = value
|
271
|
+
|
272
|
+
return JsonResponse({
|
273
|
+
"data": data,
|
274
|
+
"slugs": slugs_list,
|
275
|
+
"account": account,
|
276
|
+
"status": True
|
277
|
+
})
|
mojo/apps/metrics/utils.py
CHANGED
@@ -179,6 +179,23 @@ def generate_perm_write_key(account):
|
|
179
179
|
def generate_perm_view_key(account):
|
180
180
|
return f"mets:{account}:perm:v"
|
181
181
|
|
182
|
+
def generate_accounts_key():
|
183
|
+
return f"mets:_accounts_"
|
184
|
+
|
185
|
+
def generate_value_key(slug, account):
|
186
|
+
"""
|
187
|
+
Generate a Redis key for storing simple key-value pairs.
|
188
|
+
|
189
|
+
Args:
|
190
|
+
slug (str): The slug identifier for the value.
|
191
|
+
account (str): The account under which the value is stored.
|
192
|
+
|
193
|
+
Returns:
|
194
|
+
str: The Redis key for the value.
|
195
|
+
"""
|
196
|
+
normalized_slug = normalize_slug(slug)
|
197
|
+
return f"mets:{account}:val:{normalized_slug}"
|
198
|
+
|
182
199
|
|
183
200
|
def normalize_slug(slug):
|
184
201
|
return slug.replace(':', '|')
|
mojo/decorators/http.py
CHANGED
@@ -10,6 +10,7 @@ from mojo.helpers.response import JsonResponse
|
|
10
10
|
from functools import wraps
|
11
11
|
from mojo.helpers import modules
|
12
12
|
from mojo.models import rest
|
13
|
+
from django.http import HttpResponse
|
13
14
|
from mojo.apps import metrics
|
14
15
|
|
15
16
|
logger = logit.get_logger("error", "error.log")
|
@@ -23,6 +24,7 @@ MOJO_APPEND_SLASH = settings.get("MOJO_APPEND_SLASH", False)
|
|
23
24
|
|
24
25
|
API_METRICS = settings.get("API_METRICS", False)
|
25
26
|
API_METRICS_GRANULARITY = settings.get("API_METRICS_GRANULARITY", "days")
|
27
|
+
EVENTS_ON_ERRORS = settings.get("EVENTS_ON_ERRORS", True)
|
26
28
|
|
27
29
|
|
28
30
|
def dispatcher(request, *args, **kwargs):
|
@@ -37,6 +39,13 @@ def dispatcher(request, *args, **kwargs):
|
|
37
39
|
if request.group is not None:
|
38
40
|
request.group.touch()
|
39
41
|
except ValueError:
|
42
|
+
if EVENTS_ON_ERRORS:
|
43
|
+
rest.MojoModel.class_report_incident(
|
44
|
+
details=f"Permission denied: Invalid group ID -> '{request.DATA.group}'",
|
45
|
+
event_type="rest_error",
|
46
|
+
request=request,
|
47
|
+
request_path=getattr(request, "path", None),
|
48
|
+
)
|
40
49
|
return JsonResponse({"error": "Invalid group ID", "code": 400}, status=400)
|
41
50
|
method_key = f"{key}__{request.method}"
|
42
51
|
if method_key not in URLPATTERN_METHODS:
|
@@ -56,21 +65,51 @@ def dispatch_error_handler(func):
|
|
56
65
|
try:
|
57
66
|
if API_METRICS:
|
58
67
|
metrics.record("api_calls", category="mojo_api", min_granularity=API_METRICS_GRANULARITY)
|
59
|
-
|
68
|
+
resp = func(request, *args, **kwargs)
|
69
|
+
if not isinstance(resp, HttpResponse) and isinstance(resp, dict):
|
70
|
+
return JsonResponse(resp)
|
71
|
+
return resp
|
60
72
|
except mojo.errors.MojoException as err:
|
61
73
|
if API_METRICS:
|
62
74
|
metrics.record("api_errors", category="mojo_api", min_granularity=API_METRICS_GRANULARITY)
|
75
|
+
if EVENTS_ON_ERRORS:
|
76
|
+
rest.MojoModel.class_report_incident_for_user(
|
77
|
+
details=f"Rest Mojo Error: {err.reason}",
|
78
|
+
event_type="rest_error",
|
79
|
+
request_data=request.DATA,
|
80
|
+
request=request,
|
81
|
+
request_path=getattr(request, "path", None),
|
82
|
+
stack_trace=traceback.format_exc(),
|
83
|
+
)
|
63
84
|
return JsonResponse({"error": err.reason, "code": err.code}, status=err.status)
|
64
85
|
except ValueError as err:
|
65
86
|
if API_METRICS:
|
66
87
|
metrics.record("api_errors", category="mojo_api", min_granularity=API_METRICS_GRANULARITY)
|
67
88
|
logger.exception(f"ValueErrror: {str(err)}, Path: {request.path}, IP: {request.META.get('REMOTE_ADDR')}")
|
89
|
+
if EVENTS_ON_ERRORS:
|
90
|
+
rest.MojoModel.class_report_incident_for_user(
|
91
|
+
details=f"Rest Value Error: {err}",
|
92
|
+
event_type="rest_error",
|
93
|
+
request_data=request.DATA,
|
94
|
+
request=request,
|
95
|
+
request_path=getattr(request, "path", None),
|
96
|
+
stack_trace=traceback.format_exc()
|
97
|
+
)
|
68
98
|
return JsonResponse({"error": str(err), "code": 555 }, status=500)
|
69
99
|
except Exception as err:
|
70
100
|
if API_METRICS:
|
71
101
|
metrics.record("api_errors", category="mojo_api", min_granularity=API_METRICS_GRANULARITY)
|
72
102
|
# logger.exception(f"Unhandled REST Exception: {request.path}")
|
73
103
|
logger.exception(f"Error: {str(err)}, Path: {request.path}, IP: {request.META.get('REMOTE_ADDR')}")
|
104
|
+
if EVENTS_ON_ERRORS:
|
105
|
+
rest.MojoModel.class_report_incident_for_user(
|
106
|
+
details=f"Rest Exception: {err}",
|
107
|
+
event_type="rest_error",
|
108
|
+
request_data=request.DATA,
|
109
|
+
request=request,
|
110
|
+
stack_trace=traceback.format_exc(),
|
111
|
+
request_path=getattr(request, "path", None),
|
112
|
+
)
|
74
113
|
return JsonResponse({"error": str(err), "code": 500 }, status=500)
|
75
114
|
|
76
115
|
return wrapper
|
mojo/helpers/aws/__init__.py
CHANGED
@@ -7,6 +7,7 @@ A simple interface for working with AWS services.
|
|
7
7
|
# Import service modules - these will be implemented
|
8
8
|
from .s3 import S3Bucket, S3Item
|
9
9
|
from .client import get_session
|
10
|
+
from .kms import KMSHelper
|
10
11
|
|
11
12
|
# These will be implemented in future modules
|
12
13
|
from .iam import IAMRole, IAMPolicy, IAMUser
|
@@ -17,25 +18,28 @@ from .ec2 import EC2Instance, EC2SecurityGroup
|
|
17
18
|
__all__ = [
|
18
19
|
# Base
|
19
20
|
'get_session',
|
20
|
-
|
21
|
+
|
21
22
|
# S3
|
22
23
|
'S3Bucket',
|
23
24
|
'S3Item',
|
24
|
-
|
25
|
+
|
26
|
+
# KMS
|
27
|
+
'KMSHelper',
|
28
|
+
|
25
29
|
# IAM
|
26
30
|
'IAMRole',
|
27
31
|
'IAMPolicy',
|
28
32
|
'IAMUser',
|
29
|
-
|
33
|
+
|
30
34
|
# SES
|
31
35
|
'EmailSender',
|
32
36
|
'EmailTemplate',
|
33
|
-
|
37
|
+
|
34
38
|
# SNS
|
35
|
-
'SNSTopic',
|
39
|
+
'SNSTopic',
|
36
40
|
'SNSSubscription',
|
37
|
-
|
41
|
+
|
38
42
|
# EC2
|
39
43
|
'EC2Instance',
|
40
44
|
'EC2SecurityGroup',
|
41
|
-
]
|
45
|
+
]
|