django-nativemojo 0.1.10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. django_nativemojo-0.1.10.dist-info/LICENSE +19 -0
  2. django_nativemojo-0.1.10.dist-info/METADATA +96 -0
  3. django_nativemojo-0.1.10.dist-info/NOTICE +8 -0
  4. django_nativemojo-0.1.10.dist-info/RECORD +194 -0
  5. django_nativemojo-0.1.10.dist-info/WHEEL +4 -0
  6. mojo/__init__.py +3 -0
  7. mojo/apps/account/__init__.py +1 -0
  8. mojo/apps/account/admin.py +91 -0
  9. mojo/apps/account/apps.py +16 -0
  10. mojo/apps/account/migrations/0001_initial.py +77 -0
  11. mojo/apps/account/migrations/0002_user_is_email_verified_user_is_phone_verified.py +23 -0
  12. mojo/apps/account/migrations/0003_group_mojo_secrets_user_mojo_secrets.py +23 -0
  13. mojo/apps/account/migrations/__init__.py +0 -0
  14. mojo/apps/account/models/__init__.py +3 -0
  15. mojo/apps/account/models/group.py +98 -0
  16. mojo/apps/account/models/member.py +95 -0
  17. mojo/apps/account/models/pkey.py +18 -0
  18. mojo/apps/account/models/user.py +211 -0
  19. mojo/apps/account/rest/__init__.py +3 -0
  20. mojo/apps/account/rest/group.py +25 -0
  21. mojo/apps/account/rest/user.py +47 -0
  22. mojo/apps/account/utils/__init__.py +0 -0
  23. mojo/apps/account/utils/jwtoken.py +72 -0
  24. mojo/apps/account/utils/passkeys.py +54 -0
  25. mojo/apps/fileman/README.md +549 -0
  26. mojo/apps/fileman/__init__.py +0 -0
  27. mojo/apps/fileman/apps.py +15 -0
  28. mojo/apps/fileman/backends/__init__.py +117 -0
  29. mojo/apps/fileman/backends/base.py +319 -0
  30. mojo/apps/fileman/backends/filesystem.py +397 -0
  31. mojo/apps/fileman/backends/s3.py +398 -0
  32. mojo/apps/fileman/examples/configurations.py +378 -0
  33. mojo/apps/fileman/examples/usage_example.py +665 -0
  34. mojo/apps/fileman/management/__init__.py +1 -0
  35. mojo/apps/fileman/management/commands/__init__.py +1 -0
  36. mojo/apps/fileman/management/commands/cleanup_expired_uploads.py +222 -0
  37. mojo/apps/fileman/models/__init__.py +7 -0
  38. mojo/apps/fileman/models/file.py +292 -0
  39. mojo/apps/fileman/models/manager.py +227 -0
  40. mojo/apps/fileman/models/render.py +0 -0
  41. mojo/apps/fileman/rest/__init__ +0 -0
  42. mojo/apps/fileman/rest/__init__.py +23 -0
  43. mojo/apps/fileman/rest/fileman.py +13 -0
  44. mojo/apps/fileman/rest/upload.py +92 -0
  45. mojo/apps/fileman/utils/__init__.py +19 -0
  46. mojo/apps/fileman/utils/upload.py +616 -0
  47. mojo/apps/incident/__init__.py +1 -0
  48. mojo/apps/incident/handlers/__init__.py +3 -0
  49. mojo/apps/incident/handlers/event_handlers.py +142 -0
  50. mojo/apps/incident/migrations/0001_initial.py +83 -0
  51. mojo/apps/incident/migrations/0002_rename_bundle_ruleset_bundle_minutes_event_hostname_and_more.py +44 -0
  52. mojo/apps/incident/migrations/0003_alter_event_model_id.py +18 -0
  53. mojo/apps/incident/migrations/0004_alter_incident_model_id.py +18 -0
  54. mojo/apps/incident/migrations/__init__.py +0 -0
  55. mojo/apps/incident/models/__init__.py +3 -0
  56. mojo/apps/incident/models/event.py +135 -0
  57. mojo/apps/incident/models/incident.py +33 -0
  58. mojo/apps/incident/models/rule.py +247 -0
  59. mojo/apps/incident/parsers/__init__.py +0 -0
  60. mojo/apps/incident/parsers/ossec/__init__.py +1 -0
  61. mojo/apps/incident/parsers/ossec/core.py +82 -0
  62. mojo/apps/incident/parsers/ossec/parsed.py +23 -0
  63. mojo/apps/incident/parsers/ossec/rules.py +124 -0
  64. mojo/apps/incident/parsers/ossec/utils.py +169 -0
  65. mojo/apps/incident/reporter.py +42 -0
  66. mojo/apps/incident/rest/__init__.py +2 -0
  67. mojo/apps/incident/rest/event.py +23 -0
  68. mojo/apps/incident/rest/ossec.py +22 -0
  69. mojo/apps/logit/__init__.py +0 -0
  70. mojo/apps/logit/admin.py +37 -0
  71. mojo/apps/logit/migrations/0001_initial.py +32 -0
  72. mojo/apps/logit/migrations/0002_log_duid_log_payload_log_username.py +28 -0
  73. mojo/apps/logit/migrations/0003_log_level.py +18 -0
  74. mojo/apps/logit/migrations/__init__.py +0 -0
  75. mojo/apps/logit/models/__init__.py +1 -0
  76. mojo/apps/logit/models/log.py +57 -0
  77. mojo/apps/logit/rest.py +9 -0
  78. mojo/apps/metrics/README.md +79 -0
  79. mojo/apps/metrics/__init__.py +12 -0
  80. mojo/apps/metrics/redis_metrics.py +331 -0
  81. mojo/apps/metrics/rest/__init__.py +1 -0
  82. mojo/apps/metrics/rest/base.py +152 -0
  83. mojo/apps/metrics/rest/db.py +0 -0
  84. mojo/apps/metrics/utils.py +227 -0
  85. mojo/apps/notify/README.md +91 -0
  86. mojo/apps/notify/README_NOTIFICATIONS.md +566 -0
  87. mojo/apps/notify/__init__.py +0 -0
  88. mojo/apps/notify/admin.py +52 -0
  89. mojo/apps/notify/handlers/__init__.py +0 -0
  90. mojo/apps/notify/handlers/example_handlers.py +516 -0
  91. mojo/apps/notify/handlers/ses/__init__.py +25 -0
  92. mojo/apps/notify/handlers/ses/bounce.py +0 -0
  93. mojo/apps/notify/handlers/ses/complaint.py +25 -0
  94. mojo/apps/notify/handlers/ses/message.py +86 -0
  95. mojo/apps/notify/management/__init__.py +0 -0
  96. mojo/apps/notify/management/commands/__init__.py +1 -0
  97. mojo/apps/notify/management/commands/process_notifications.py +370 -0
  98. mojo/apps/notify/mod +0 -0
  99. mojo/apps/notify/models/__init__.py +12 -0
  100. mojo/apps/notify/models/account.py +128 -0
  101. mojo/apps/notify/models/attachment.py +24 -0
  102. mojo/apps/notify/models/bounce.py +68 -0
  103. mojo/apps/notify/models/complaint.py +40 -0
  104. mojo/apps/notify/models/inbox.py +113 -0
  105. mojo/apps/notify/models/inbox_message.py +173 -0
  106. mojo/apps/notify/models/outbox.py +129 -0
  107. mojo/apps/notify/models/outbox_message.py +288 -0
  108. mojo/apps/notify/models/template.py +30 -0
  109. mojo/apps/notify/providers/__init__.py +0 -0
  110. mojo/apps/notify/providers/aws.py +73 -0
  111. mojo/apps/notify/rest/__init__.py +0 -0
  112. mojo/apps/notify/rest/ses.py +0 -0
  113. mojo/apps/notify/utils/__init__.py +2 -0
  114. mojo/apps/notify/utils/notifications.py +404 -0
  115. mojo/apps/notify/utils/parsing.py +202 -0
  116. mojo/apps/notify/utils/render.py +144 -0
  117. mojo/apps/tasks/README.md +118 -0
  118. mojo/apps/tasks/__init__.py +11 -0
  119. mojo/apps/tasks/manager.py +489 -0
  120. mojo/apps/tasks/rest/__init__.py +2 -0
  121. mojo/apps/tasks/rest/hooks.py +0 -0
  122. mojo/apps/tasks/rest/tasks.py +62 -0
  123. mojo/apps/tasks/runner.py +174 -0
  124. mojo/apps/tasks/tq_handlers.py +14 -0
  125. mojo/decorators/__init__.py +3 -0
  126. mojo/decorators/auth.py +25 -0
  127. mojo/decorators/cron.py +31 -0
  128. mojo/decorators/http.py +132 -0
  129. mojo/decorators/validate.py +14 -0
  130. mojo/errors.py +88 -0
  131. mojo/helpers/__init__.py +0 -0
  132. mojo/helpers/aws/__init__.py +0 -0
  133. mojo/helpers/aws/client.py +8 -0
  134. mojo/helpers/aws/s3.py +268 -0
  135. mojo/helpers/aws/setup_email.py +0 -0
  136. mojo/helpers/cron.py +79 -0
  137. mojo/helpers/crypto/__init__.py +4 -0
  138. mojo/helpers/crypto/aes.py +60 -0
  139. mojo/helpers/crypto/hash.py +59 -0
  140. mojo/helpers/crypto/privpub/__init__.py +1 -0
  141. mojo/helpers/crypto/privpub/hybrid.py +97 -0
  142. mojo/helpers/crypto/privpub/rsa.py +104 -0
  143. mojo/helpers/crypto/sign.py +36 -0
  144. mojo/helpers/crypto/too.l.py +25 -0
  145. mojo/helpers/crypto/utils.py +26 -0
  146. mojo/helpers/daemon.py +94 -0
  147. mojo/helpers/dates.py +69 -0
  148. mojo/helpers/dns/__init__.py +0 -0
  149. mojo/helpers/dns/godaddy.py +62 -0
  150. mojo/helpers/filetypes.py +128 -0
  151. mojo/helpers/logit.py +310 -0
  152. mojo/helpers/modules.py +95 -0
  153. mojo/helpers/paths.py +63 -0
  154. mojo/helpers/redis.py +10 -0
  155. mojo/helpers/request.py +89 -0
  156. mojo/helpers/request_parser.py +269 -0
  157. mojo/helpers/response.py +14 -0
  158. mojo/helpers/settings.py +146 -0
  159. mojo/helpers/sysinfo.py +140 -0
  160. mojo/helpers/ua.py +0 -0
  161. mojo/middleware/__init__.py +0 -0
  162. mojo/middleware/auth.py +26 -0
  163. mojo/middleware/logging.py +55 -0
  164. mojo/middleware/mojo.py +21 -0
  165. mojo/migrations/0001_initial.py +32 -0
  166. mojo/migrations/__init__.py +0 -0
  167. mojo/models/__init__.py +2 -0
  168. mojo/models/meta.py +262 -0
  169. mojo/models/rest.py +538 -0
  170. mojo/models/secrets.py +59 -0
  171. mojo/rest/__init__.py +1 -0
  172. mojo/rest/info.py +26 -0
  173. mojo/serializers/__init__.py +0 -0
  174. mojo/serializers/models.py +165 -0
  175. mojo/serializers/openapi.py +188 -0
  176. mojo/urls.py +38 -0
  177. mojo/ws4redis/README.md +174 -0
  178. mojo/ws4redis/__init__.py +2 -0
  179. mojo/ws4redis/client.py +283 -0
  180. mojo/ws4redis/connection.py +327 -0
  181. mojo/ws4redis/exceptions.py +32 -0
  182. mojo/ws4redis/redis.py +183 -0
  183. mojo/ws4redis/servers/__init__.py +0 -0
  184. mojo/ws4redis/servers/base.py +86 -0
  185. mojo/ws4redis/servers/django.py +171 -0
  186. mojo/ws4redis/servers/uwsgi.py +63 -0
  187. mojo/ws4redis/settings.py +45 -0
  188. mojo/ws4redis/utf8validator.py +128 -0
  189. mojo/ws4redis/websocket.py +403 -0
  190. testit/__init__.py +0 -0
  191. testit/client.py +147 -0
  192. testit/faker.py +20 -0
  193. testit/helpers.py +198 -0
  194. testit/runner.py +262 -0
@@ -0,0 +1,319 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Dict, Any, Optional, Tuple, List
3
+ from datetime import datetime, timedelta
4
+ import os
5
+
6
+
7
+ class StorageBackend(ABC):
8
+ """
9
+ Abstract base class for all storage backends
10
+ """
11
+
12
+ def __init__(self, file_manager, **kwargs):
13
+ """
14
+ Initialize the storage backend with a FileManager instance
15
+
16
+ Args:
17
+ file_manager: FileManager instance with configuration
18
+ **kwargs: Additional backend-specific configuration
19
+ """
20
+ self.file_manager = file_manager
21
+ self.settings = file_manager.settings
22
+ self.backend_url = file_manager.backend_url
23
+ self.config = kwargs
24
+
25
+ @abstractmethod
26
+ def save(self, file_obj, filename: str, **kwargs) -> str:
27
+ """
28
+ Save a file to the storage backend
29
+
30
+ Args:
31
+ file_obj: File-like object to save
32
+ filename: Name to save the file as
33
+ **kwargs: Additional save options
34
+
35
+ Returns:
36
+ str: Full path to the saved file
37
+ """
38
+ pass
39
+
40
+ @abstractmethod
41
+ def delete(self, file_path: str) -> bool:
42
+ """
43
+ Delete a file from the storage backend
44
+
45
+ Args:
46
+ file_path: Path to the file to delete
47
+
48
+ Returns:
49
+ bool: True if deletion was successful
50
+ """
51
+ pass
52
+
53
+ @abstractmethod
54
+ def exists(self, file_path: str) -> bool:
55
+ """
56
+ Check if a file exists in the storage backend
57
+
58
+ Args:
59
+ file_path: Path to check
60
+
61
+ Returns:
62
+ bool: True if file exists
63
+ """
64
+ pass
65
+
66
+ @abstractmethod
67
+ def get_file_size(self, file_path: str) -> Optional[int]:
68
+ """
69
+ Get the size of a file in bytes
70
+
71
+ Args:
72
+ file_path: Path to the file
73
+
74
+ Returns:
75
+ Optional[int]: File size in bytes, None if file doesn't exist
76
+ """
77
+ pass
78
+
79
+ @abstractmethod
80
+ def get_url(self, file_path: str, expires_in: Optional[int] = None) -> str:
81
+ """
82
+ Get a URL to access the file
83
+
84
+ Args:
85
+ file_path: Path to the file
86
+ expires_in: Optional expiration time in seconds
87
+
88
+ Returns:
89
+ str: URL to access the file
90
+ """
91
+ pass
92
+
93
+ @abstractmethod
94
+ def generate_upload_url(self, file_path: str, content_type: str,
95
+ file_size: Optional[int] = None,
96
+ expires_in: int = 3600) -> Dict[str, Any]:
97
+ """
98
+ Generate a pre-signed URL for direct upload
99
+
100
+ Args:
101
+ file_path: Path where the file will be stored
102
+ content_type: MIME type of the file
103
+ file_size: Expected file size in bytes
104
+ expires_in: URL expiration time in seconds
105
+
106
+ Returns:
107
+ Dict containing:
108
+ - upload_url: Pre-signed upload URL
109
+ - method: HTTP method to use (POST, PUT, etc.)
110
+ - fields: Additional form fields (if any)
111
+ - headers: Required headers (if any)
112
+ """
113
+ pass
114
+
115
+ def supports_direct_upload(self) -> bool:
116
+ """
117
+ Check if this backend supports direct uploads
118
+
119
+ Returns:
120
+ bool: True if direct uploads are supported
121
+ """
122
+ return self.file_manager.supports_direct_upload
123
+
124
+ def validate_upload(self, file_path: str, upload_token: str,
125
+ expected_size: Optional[int] = None,
126
+ expected_checksum: Optional[str] = None) -> Tuple[bool, str]:
127
+ """
128
+ Validate that an uploaded file matches expectations
129
+
130
+ Args:
131
+ file_path: Path to the uploaded file
132
+ upload_token: Token used for the upload
133
+ expected_size: Expected file size
134
+ expected_checksum: Expected file checksum
135
+
136
+ Returns:
137
+ Tuple[bool, str]: (is_valid, error_message)
138
+ """
139
+ if not self.exists(file_path):
140
+ return False, "File does not exist after upload"
141
+
142
+ if expected_size:
143
+ actual_size = self.get_file_size(file_path)
144
+ if actual_size != expected_size:
145
+ return False, f"File size mismatch: expected {expected_size}, got {actual_size}"
146
+
147
+ if expected_checksum:
148
+ actual_checksum = self.get_file_checksum(file_path)
149
+ if actual_checksum != expected_checksum:
150
+ return False, f"Checksum mismatch: expected {expected_checksum}, got {actual_checksum}"
151
+
152
+ return True, "Upload validation successful"
153
+
154
+ def get_file_checksum(self, file_path: str, algorithm: str = 'md5') -> Optional[str]:
155
+ """
156
+ Calculate checksum of a file
157
+
158
+ Args:
159
+ file_path: Path to the file
160
+ algorithm: Hash algorithm to use (md5, sha256, etc.)
161
+
162
+ Returns:
163
+ Optional[str]: File checksum, None if calculation fails
164
+ """
165
+ # Default implementation - backends can override for efficiency
166
+ try:
167
+ import hashlib
168
+ hash_obj = hashlib.new(algorithm)
169
+
170
+ with self.open(file_path, 'rb') as f:
171
+ for chunk in iter(lambda: f.read(4096), b""):
172
+ hash_obj.update(chunk)
173
+
174
+ return hash_obj.hexdigest()
175
+ except Exception:
176
+ return None
177
+
178
+ def open(self, file_path: str, mode: str = 'rb'):
179
+ """
180
+ Open a file from the storage backend
181
+
182
+ Args:
183
+ file_path: Path to the file
184
+ mode: File open mode
185
+
186
+ Returns:
187
+ File-like object
188
+ """
189
+ raise NotImplementedError("Backend does not support file opening")
190
+
191
+ def generate_file_path(self, filename: str, group_id: Optional[int] = None) -> str:
192
+ """
193
+ Generate a storage path for a file
194
+
195
+ Args:
196
+ filename: Original filename
197
+ group_id: Optional group ID for organization
198
+
199
+ Returns:
200
+ str: Generated file path
201
+ """
202
+ # Default implementation - backends can override
203
+ parts = []
204
+
205
+ if group_id:
206
+ parts.append(f"group_{group_id}")
207
+
208
+ # Add date-based organization
209
+ now = datetime.now()
210
+ parts.extend([
211
+ str(now.year),
212
+ f"{now.month:02d}",
213
+ f"{now.day:02d}"
214
+ ])
215
+
216
+ parts.append(filename)
217
+ return "/".join(parts)
218
+
219
+ def get_available_space(self) -> Optional[int]:
220
+ """
221
+ Get available storage space in bytes
222
+
223
+ Returns:
224
+ Optional[int]: Available space in bytes, None if unlimited/unknown
225
+ """
226
+ return None
227
+
228
+ def cleanup_expired_uploads(self, before_date: Optional[datetime] = None):
229
+ """
230
+ Clean up expired upload URLs and temporary files
231
+
232
+ Args:
233
+ before_date: Clean up uploads before this date (default: now)
234
+ """
235
+ # Default implementation does nothing - backends can override
236
+ pass
237
+
238
+ def get_file_metadata(self, file_path: str) -> Dict[str, Any]:
239
+ """
240
+ Get metadata for a file
241
+
242
+ Args:
243
+ file_path: Path to the file
244
+
245
+ Returns:
246
+ Dict containing file metadata
247
+ """
248
+ metadata = {}
249
+
250
+ if self.exists(file_path):
251
+ metadata['exists'] = True
252
+ metadata['size'] = self.get_file_size(file_path)
253
+ metadata['path'] = file_path
254
+ else:
255
+ metadata['exists'] = False
256
+
257
+ return metadata
258
+
259
+ def copy_file(self, source_path: str, dest_path: str) -> bool:
260
+ """
261
+ Copy a file within the storage backend
262
+
263
+ Args:
264
+ source_path: Source file path
265
+ dest_path: Destination file path
266
+
267
+ Returns:
268
+ bool: True if copy was successful
269
+ """
270
+ try:
271
+ with self.open(source_path, 'rb') as source:
272
+ return self.save(source, dest_path) is not None
273
+ except Exception:
274
+ return False
275
+
276
+ def move_file(self, source_path: str, dest_path: str) -> bool:
277
+ """
278
+ Move a file within the storage backend
279
+
280
+ Args:
281
+ source_path: Source file path
282
+ dest_path: Destination file path
283
+
284
+ Returns:
285
+ bool: True if move was successful
286
+ """
287
+ if self.copy_file(source_path, dest_path):
288
+ return self.delete(source_path)
289
+ return False
290
+
291
+ def list_files(self, path_prefix: str = "", limit: int = 1000) -> List[str]:
292
+ """
293
+ List files with optional path prefix
294
+
295
+ Args:
296
+ path_prefix: Optional path prefix to filter by
297
+ limit: Maximum number of files to return
298
+
299
+ Returns:
300
+ List[str]: List of file paths
301
+ """
302
+ # Default implementation returns empty list - backends should override
303
+ return []
304
+
305
+ def get_setting(self, key: str, default: Any = None) -> Any:
306
+ """
307
+ Get a setting value from the file manager configuration
308
+
309
+ Args:
310
+ key: Setting key
311
+ default: Default value if key not found
312
+
313
+ Returns:
314
+ Setting value
315
+ """
316
+ return self.settings.get(key, default)
317
+
318
+ def __str__(self):
319
+ return f"{self.__class__.__name__}({self.backend_url})"