django-nativemojo 0.1.10__py3-none-any.whl → 0.1.15__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/METADATA +136 -0
- {django_nativemojo-0.1.10.dist-info → django_nativemojo-0.1.15.dist-info}/RECORD +105 -65
- mojo/__init__.py +1 -1
- mojo/apps/account/management/__init__.py +5 -0
- mojo/apps/account/management/commands/__init__.py +6 -0
- mojo/apps/account/management/commands/serializer_admin.py +531 -0
- mojo/apps/account/migrations/0004_user_avatar.py +20 -0
- mojo/apps/account/migrations/0005_group_last_activity.py +18 -0
- mojo/apps/account/models/group.py +25 -7
- mojo/apps/account/models/member.py +15 -4
- mojo/apps/account/models/user.py +197 -20
- mojo/apps/account/rest/group.py +1 -0
- mojo/apps/account/rest/user.py +6 -2
- mojo/apps/aws/rest/__init__.py +1 -0
- mojo/apps/aws/rest/s3.py +64 -0
- mojo/apps/fileman/README.md +8 -8
- mojo/apps/fileman/backends/base.py +76 -70
- mojo/apps/fileman/backends/filesystem.py +86 -86
- mojo/apps/fileman/backends/s3.py +200 -108
- mojo/apps/fileman/migrations/0001_initial.py +106 -0
- mojo/apps/fileman/migrations/0002_filemanager_parent_alter_filemanager_max_file_size.py +24 -0
- mojo/apps/fileman/migrations/0003_remove_file_fileman_fil_upload__c4bc35_idx_and_more.py +25 -0
- mojo/apps/fileman/migrations/0004_remove_file_original_filename_and_more.py +39 -0
- mojo/apps/fileman/migrations/0005_alter_file_upload_token.py +18 -0
- mojo/apps/fileman/migrations/0006_file_download_url_filemanager_forever_urls.py +23 -0
- mojo/apps/fileman/migrations/0007_remove_filemanager_forever_urls_and_more.py +22 -0
- mojo/apps/fileman/migrations/0008_file_category.py +18 -0
- mojo/apps/fileman/migrations/0009_rename_file_path_file_storage_file_path.py +18 -0
- mojo/apps/fileman/migrations/0010_filerendition.py +33 -0
- mojo/apps/fileman/migrations/0011_alter_filerendition_original_file.py +19 -0
- mojo/apps/fileman/models/__init__.py +1 -5
- mojo/apps/fileman/models/file.py +204 -58
- mojo/apps/fileman/models/manager.py +161 -31
- mojo/apps/fileman/models/rendition.py +118 -0
- mojo/apps/fileman/renderer/__init__.py +111 -0
- mojo/apps/fileman/renderer/audio.py +403 -0
- mojo/apps/fileman/renderer/base.py +205 -0
- mojo/apps/fileman/renderer/document.py +404 -0
- mojo/apps/fileman/renderer/image.py +222 -0
- mojo/apps/fileman/renderer/utils.py +297 -0
- mojo/apps/fileman/renderer/video.py +304 -0
- mojo/apps/fileman/rest/__init__.py +1 -18
- mojo/apps/fileman/rest/upload.py +22 -32
- mojo/apps/fileman/signals.py +58 -0
- mojo/apps/fileman/tasks.py +254 -0
- mojo/apps/fileman/utils/__init__.py +40 -16
- mojo/apps/incident/migrations/0005_incidenthistory.py +39 -0
- mojo/apps/incident/migrations/0006_alter_incident_state.py +18 -0
- mojo/apps/incident/models/__init__.py +1 -0
- mojo/apps/incident/models/history.py +36 -0
- mojo/apps/incident/models/incident.py +1 -1
- mojo/apps/incident/reporter.py +3 -1
- mojo/apps/incident/rest/event.py +7 -1
- mojo/apps/logit/migrations/0004_alter_log_level.py +18 -0
- mojo/apps/logit/models/log.py +4 -1
- mojo/apps/metrics/utils.py +2 -2
- mojo/apps/notify/handlers/ses/message.py +1 -1
- mojo/apps/notify/providers/aws.py +2 -2
- mojo/apps/tasks/__init__.py +34 -1
- mojo/apps/tasks/manager.py +200 -45
- mojo/apps/tasks/rest/tasks.py +24 -10
- mojo/apps/tasks/runner.py +283 -18
- mojo/apps/tasks/task.py +99 -0
- mojo/apps/tasks/tq_handlers.py +118 -0
- mojo/decorators/auth.py +6 -1
- mojo/decorators/http.py +7 -2
- mojo/helpers/aws/__init__.py +41 -0
- mojo/helpers/aws/ec2.py +804 -0
- mojo/helpers/aws/iam.py +748 -0
- mojo/helpers/aws/s3.py +451 -11
- mojo/helpers/aws/ses.py +483 -0
- mojo/helpers/aws/sns.py +461 -0
- 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/dates.py +18 -0
- mojo/helpers/response.py +6 -2
- mojo/helpers/settings/__init__.py +2 -0
- mojo/helpers/{settings.py → settings/helper.py} +1 -37
- mojo/helpers/settings/parser.py +132 -0
- mojo/middleware/logging.py +1 -1
- mojo/middleware/mojo.py +5 -0
- mojo/models/rest.py +261 -46
- mojo/models/secrets.py +13 -4
- mojo/serializers/__init__.py +100 -0
- mojo/serializers/advanced/README.md +363 -0
- mojo/serializers/advanced/__init__.py +247 -0
- mojo/serializers/advanced/formats/__init__.py +28 -0
- mojo/serializers/advanced/formats/csv.py +416 -0
- mojo/serializers/advanced/formats/excel.py +516 -0
- mojo/serializers/advanced/formats/json.py +239 -0
- mojo/serializers/advanced/formats/localizers.py +509 -0
- mojo/serializers/advanced/formats/response.py +485 -0
- mojo/serializers/advanced/serializer.py +568 -0
- mojo/serializers/manager.py +501 -0
- mojo/serializers/optimized.py +618 -0
- mojo/serializers/settings_example.py +322 -0
- mojo/serializers/{models.py → simple.py} +38 -15
- testit/helpers.py +21 -4
- django_nativemojo-0.1.10.dist-info/METADATA +0 -96
- mojo/apps/metrics/rest/db.py +0 -0
- mojo/helpers/aws/setup_email.py +0 -0
- mojo/ws4redis/README.md +0 -174
- mojo/ws4redis/__init__.py +0 -2
- mojo/ws4redis/client.py +0 -283
- mojo/ws4redis/connection.py +0 -327
- mojo/ws4redis/exceptions.py +0 -32
- mojo/ws4redis/redis.py +0 -183
- mojo/ws4redis/servers/base.py +0 -86
- mojo/ws4redis/servers/django.py +0 -171
- mojo/ws4redis/servers/uwsgi.py +0 -63
- mojo/ws4redis/settings.py +0 -45
- mojo/ws4redis/utf8validator.py +0 -128
- mojo/ws4redis/websocket.py +0 -403
- {django_nativemojo-0.1.10.dist-info → django_nativemojo-0.1.15.dist-info}/LICENSE +0 -0
- {django_nativemojo-0.1.10.dist-info → django_nativemojo-0.1.15.dist-info}/NOTICE +0 -0
- {django_nativemojo-0.1.10.dist-info → django_nativemojo-0.1.15.dist-info}/WHEEL +0 -0
- /mojo/{ws4redis/servers → apps/aws}/__init__.py +0 -0
- /mojo/apps/{fileman/models/render.py → aws/models/__init__.py} +0 -0
- /mojo/apps/fileman/{rest/__init__ → migrations/__init__.py} +0 -0
@@ -0,0 +1,239 @@
|
|
1
|
+
import json
|
2
|
+
import datetime
|
3
|
+
import math
|
4
|
+
from decimal import Decimal
|
5
|
+
|
6
|
+
# Try to import ujson for better performance
|
7
|
+
try:
|
8
|
+
import ujson
|
9
|
+
HAS_UJSON = True
|
10
|
+
except ImportError:
|
11
|
+
ujson = None
|
12
|
+
HAS_UJSON = False
|
13
|
+
|
14
|
+
from mojo.helpers import logit
|
15
|
+
|
16
|
+
logger = logit.get_logger("json_formatter", "json_formatter.log")
|
17
|
+
|
18
|
+
|
19
|
+
class JsonFormatter:
|
20
|
+
"""
|
21
|
+
Enhanced JSON formatter with performance optimizations and Django model support.
|
22
|
+
"""
|
23
|
+
|
24
|
+
def __init__(self, use_ujson=None, pretty=False, ensure_ascii=False):
|
25
|
+
"""
|
26
|
+
Initialize JSON formatter.
|
27
|
+
|
28
|
+
:param use_ujson: Force use of ujson (True/False) or auto-detect (None)
|
29
|
+
:param pretty: Enable pretty printing with indentation
|
30
|
+
:param ensure_ascii: Ensure ASCII output (escapes unicode)
|
31
|
+
"""
|
32
|
+
self.use_ujson = use_ujson if use_ujson is not None else HAS_UJSON
|
33
|
+
self.pretty = pretty
|
34
|
+
self.ensure_ascii = ensure_ascii
|
35
|
+
|
36
|
+
def serialize(self, data, **kwargs):
|
37
|
+
"""
|
38
|
+
Serialize data to JSON string.
|
39
|
+
|
40
|
+
:param data: Data to serialize
|
41
|
+
:param kwargs: Additional options for JSON serialization
|
42
|
+
:return: JSON string
|
43
|
+
"""
|
44
|
+
# Preprocess data to handle Django types
|
45
|
+
processed_data = self._preprocess_data(data)
|
46
|
+
|
47
|
+
try:
|
48
|
+
if self.use_ujson and HAS_UJSON and not self.pretty:
|
49
|
+
# ujson is faster but doesn't support pretty printing or custom encoders
|
50
|
+
return ujson.dumps(processed_data, ensure_ascii=self.ensure_ascii, **kwargs)
|
51
|
+
else:
|
52
|
+
# Use standard json with custom encoder
|
53
|
+
json_kwargs = {
|
54
|
+
'cls': ExtendedJSONEncoder,
|
55
|
+
'ensure_ascii': self.ensure_ascii,
|
56
|
+
**kwargs
|
57
|
+
}
|
58
|
+
|
59
|
+
if self.pretty:
|
60
|
+
json_kwargs.update({
|
61
|
+
'indent': 4,
|
62
|
+
'separators': (',', ': '),
|
63
|
+
'sort_keys': True
|
64
|
+
})
|
65
|
+
|
66
|
+
return json.dumps(processed_data, **json_kwargs)
|
67
|
+
|
68
|
+
except Exception as e:
|
69
|
+
logger.error(f"JSON serialization failed: {e}")
|
70
|
+
logger.error(f"Data type: {type(data)}")
|
71
|
+
|
72
|
+
# Fallback to string representation
|
73
|
+
try:
|
74
|
+
return json.dumps({
|
75
|
+
'error': 'Serialization failed',
|
76
|
+
'message': str(e),
|
77
|
+
'data_type': str(type(data))
|
78
|
+
})
|
79
|
+
except Exception:
|
80
|
+
return '{"error": "Critical serialization failure"}'
|
81
|
+
|
82
|
+
def _preprocess_data(self, data):
|
83
|
+
"""
|
84
|
+
Recursively preprocess data to handle Django-specific types.
|
85
|
+
This is needed for ujson which doesn't support custom encoders.
|
86
|
+
"""
|
87
|
+
if isinstance(data, dict):
|
88
|
+
return {key: self._preprocess_data(value) for key, value in data.items()}
|
89
|
+
elif isinstance(data, (list, tuple)):
|
90
|
+
return [self._preprocess_data(item) for item in data]
|
91
|
+
elif isinstance(data, datetime.datetime):
|
92
|
+
return int(data.timestamp())
|
93
|
+
elif isinstance(data, datetime.date):
|
94
|
+
return data.isoformat()
|
95
|
+
elif isinstance(data, datetime.time):
|
96
|
+
return data.isoformat()
|
97
|
+
elif isinstance(data, Decimal):
|
98
|
+
return 0.0 if data.is_nan() else float(data)
|
99
|
+
elif isinstance(data, float):
|
100
|
+
return 0.0 if math.isnan(data) else data
|
101
|
+
elif isinstance(data, set):
|
102
|
+
return list(data)
|
103
|
+
elif hasattr(data, 'pk') and hasattr(data, '_meta'):
|
104
|
+
# Django model instance - return primary key
|
105
|
+
return data.pk
|
106
|
+
elif hasattr(data, '__dict__') and not isinstance(data, (str, bytes)):
|
107
|
+
# Generic object - try to serialize its dict
|
108
|
+
try:
|
109
|
+
return self._preprocess_data(data.__dict__)
|
110
|
+
except Exception:
|
111
|
+
return str(data)
|
112
|
+
else:
|
113
|
+
return data
|
114
|
+
|
115
|
+
def pretty_serialize(self, data, **kwargs):
|
116
|
+
"""
|
117
|
+
Serialize data with pretty formatting.
|
118
|
+
"""
|
119
|
+
old_pretty = self.pretty
|
120
|
+
self.pretty = True
|
121
|
+
try:
|
122
|
+
result = self.serialize(data, **kwargs)
|
123
|
+
finally:
|
124
|
+
self.pretty = old_pretty
|
125
|
+
return result
|
126
|
+
|
127
|
+
def compact_serialize(self, data, **kwargs):
|
128
|
+
"""
|
129
|
+
Serialize data in compact format (no extra whitespace).
|
130
|
+
"""
|
131
|
+
old_pretty = self.pretty
|
132
|
+
self.pretty = False
|
133
|
+
try:
|
134
|
+
result = self.serialize(data, **kwargs)
|
135
|
+
finally:
|
136
|
+
self.pretty = old_pretty
|
137
|
+
return result
|
138
|
+
|
139
|
+
|
140
|
+
class ExtendedJSONEncoder(json.JSONEncoder):
|
141
|
+
"""
|
142
|
+
Extended JSON encoder that handles Django model types and other Python objects.
|
143
|
+
"""
|
144
|
+
|
145
|
+
def default(self, o):
|
146
|
+
"""
|
147
|
+
Convert objects that aren't natively JSON serializable.
|
148
|
+
"""
|
149
|
+
# Handle datetime objects
|
150
|
+
if isinstance(o, datetime.datetime):
|
151
|
+
return int(o.timestamp())
|
152
|
+
elif isinstance(o, datetime.date):
|
153
|
+
return o.isoformat()
|
154
|
+
elif isinstance(o, datetime.time):
|
155
|
+
return o.isoformat()
|
156
|
+
|
157
|
+
# Handle numeric types
|
158
|
+
elif isinstance(o, Decimal):
|
159
|
+
return 0.0 if o.is_nan() else float(o)
|
160
|
+
elif isinstance(o, float) and math.isnan(o):
|
161
|
+
return 0.0
|
162
|
+
elif isinstance(o, complex):
|
163
|
+
return {'real': o.real, 'imag': o.imag}
|
164
|
+
|
165
|
+
# Handle collections
|
166
|
+
elif isinstance(o, set):
|
167
|
+
return list(o)
|
168
|
+
elif isinstance(o, frozenset):
|
169
|
+
return list(o)
|
170
|
+
|
171
|
+
# Handle bytes
|
172
|
+
elif isinstance(o, (bytes, bytearray)):
|
173
|
+
try:
|
174
|
+
return o.decode('utf-8')
|
175
|
+
except UnicodeDecodeError:
|
176
|
+
return o.decode('utf-8', errors='replace')
|
177
|
+
|
178
|
+
# Handle Django model instances
|
179
|
+
elif hasattr(o, 'pk') and hasattr(o, '_meta'):
|
180
|
+
return o.pk
|
181
|
+
|
182
|
+
# Handle Django QuerySet
|
183
|
+
elif hasattr(o, 'model') and hasattr(o, 'query'):
|
184
|
+
return list(o.values())
|
185
|
+
|
186
|
+
# Handle callable objects
|
187
|
+
elif callable(o):
|
188
|
+
try:
|
189
|
+
return o()
|
190
|
+
except Exception:
|
191
|
+
return f"<callable: {o.__name__ if hasattr(o, '__name__') else str(o)}>"
|
192
|
+
|
193
|
+
# Handle objects with __dict__
|
194
|
+
elif hasattr(o, '__dict__'):
|
195
|
+
try:
|
196
|
+
return o.__dict__
|
197
|
+
except Exception:
|
198
|
+
pass
|
199
|
+
|
200
|
+
# Try to convert to string as last resort
|
201
|
+
try:
|
202
|
+
return str(o)
|
203
|
+
except Exception:
|
204
|
+
return f"<unserializable: {type(o).__name__}>"
|
205
|
+
|
206
|
+
|
207
|
+
# Convenience functions
|
208
|
+
def to_json(data, pretty=False, use_ujson=None, **kwargs):
|
209
|
+
"""
|
210
|
+
Convert data to JSON string.
|
211
|
+
|
212
|
+
:param data: Data to serialize
|
213
|
+
:param pretty: Enable pretty printing
|
214
|
+
:param use_ujson: Force ujson usage
|
215
|
+
:param kwargs: Additional JSON options
|
216
|
+
:return: JSON string
|
217
|
+
"""
|
218
|
+
formatter = JsonFormatter(use_ujson=use_ujson, pretty=pretty)
|
219
|
+
return formatter.serialize(data, **kwargs)
|
220
|
+
|
221
|
+
|
222
|
+
def to_pretty_json(data, **kwargs):
|
223
|
+
"""
|
224
|
+
Convert data to pretty-formatted JSON string.
|
225
|
+
"""
|
226
|
+
return to_json(data, pretty=True, **kwargs)
|
227
|
+
|
228
|
+
|
229
|
+
def to_compact_json(data, **kwargs):
|
230
|
+
"""
|
231
|
+
Convert data to compact JSON string.
|
232
|
+
"""
|
233
|
+
return to_json(data, pretty=False, **kwargs)
|
234
|
+
|
235
|
+
|
236
|
+
# Legacy compatibility
|
237
|
+
serialize = to_json
|
238
|
+
pretty_json = to_pretty_json
|
239
|
+
prettyJSON = to_pretty_json # Maintain old naming convention
|