django-cfg 1.2.20__py3-none-any.whl → 1.2.22__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 (59) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/maintenance/admin/site_admin.py +47 -8
  3. django_cfg/apps/maintenance/migrations/0003_cloudflaresite_include_subdomains_and_more.py +27 -0
  4. django_cfg/apps/maintenance/models/cloudflare_site.py +41 -0
  5. django_cfg/apps/maintenance/services/maintenance_service.py +121 -32
  6. django_cfg/apps/maintenance/services/site_sync_service.py +56 -11
  7. django_cfg/apps/newsletter/signals.py +9 -8
  8. django_cfg/apps/payments/__init__.py +8 -0
  9. django_cfg/apps/payments/apps.py +22 -0
  10. django_cfg/apps/payments/managers/__init__.py +22 -0
  11. django_cfg/apps/payments/managers/api_key_manager.py +35 -0
  12. django_cfg/apps/payments/managers/balance_manager.py +361 -0
  13. django_cfg/apps/payments/managers/currency_manager.py +32 -0
  14. django_cfg/apps/payments/managers/payment_manager.py +44 -0
  15. django_cfg/apps/payments/managers/subscription_manager.py +37 -0
  16. django_cfg/apps/payments/managers/tariff_manager.py +29 -0
  17. django_cfg/apps/payments/middleware/__init__.py +13 -0
  18. django_cfg/apps/payments/migrations/0001_initial.py +982 -0
  19. django_cfg/apps/payments/migrations/__init__.py +1 -0
  20. django_cfg/apps/payments/models/__init__.py +49 -0
  21. django_cfg/apps/payments/models/api_keys.py +96 -0
  22. django_cfg/apps/payments/models/balance.py +209 -0
  23. django_cfg/apps/payments/models/base.py +14 -0
  24. django_cfg/apps/payments/models/currencies.py +138 -0
  25. django_cfg/apps/payments/models/events.py +73 -0
  26. django_cfg/apps/payments/models/payments.py +301 -0
  27. django_cfg/apps/payments/models/subscriptions.py +270 -0
  28. django_cfg/apps/payments/models/tariffs.py +102 -0
  29. django_cfg/apps/payments/serializers/__init__.py +56 -0
  30. django_cfg/apps/payments/serializers/api_keys.py +51 -0
  31. django_cfg/apps/payments/serializers/balance.py +59 -0
  32. django_cfg/apps/payments/serializers/currencies.py +55 -0
  33. django_cfg/apps/payments/serializers/payments.py +62 -0
  34. django_cfg/apps/payments/serializers/subscriptions.py +71 -0
  35. django_cfg/apps/payments/serializers/tariffs.py +56 -0
  36. django_cfg/apps/payments/services/__init__.py +14 -0
  37. django_cfg/apps/payments/services/base.py +68 -0
  38. django_cfg/apps/payments/services/nowpayments.py +78 -0
  39. django_cfg/apps/payments/services/providers.py +77 -0
  40. django_cfg/apps/payments/services/redis_service.py +215 -0
  41. django_cfg/apps/payments/urls.py +78 -0
  42. django_cfg/apps/payments/views/__init__.py +62 -0
  43. django_cfg/apps/payments/views/api_key_views.py +164 -0
  44. django_cfg/apps/payments/views/balance_views.py +75 -0
  45. django_cfg/apps/payments/views/currency_views.py +111 -0
  46. django_cfg/apps/payments/views/payment_views.py +111 -0
  47. django_cfg/apps/payments/views/subscription_views.py +135 -0
  48. django_cfg/apps/payments/views/tariff_views.py +131 -0
  49. django_cfg/core/config.py +26 -1
  50. django_cfg/core/generation.py +2 -1
  51. django_cfg/management/commands/check_settings.py +54 -0
  52. django_cfg/models/revolution.py +14 -0
  53. django_cfg/modules/base.py +9 -0
  54. django_cfg/utils/smart_defaults.py +211 -85
  55. {django_cfg-1.2.20.dist-info → django_cfg-1.2.22.dist-info}/METADATA +1 -1
  56. {django_cfg-1.2.20.dist-info → django_cfg-1.2.22.dist-info}/RECORD +59 -17
  57. {django_cfg-1.2.20.dist-info → django_cfg-1.2.22.dist-info}/WHEEL +0 -0
  58. {django_cfg-1.2.20.dist-info → django_cfg-1.2.22.dist-info}/entry_points.txt +0 -0
  59. {django_cfg-1.2.20.dist-info → django_cfg-1.2.22.dist-info}/licenses/LICENSE +0 -0
@@ -168,7 +168,8 @@ class SmartDefaults:
168
168
  domains: List[str],
169
169
  environment: Optional[str] = None,
170
170
  debug: bool = False,
171
- ssl_redirect: Optional[bool] = None
171
+ ssl_redirect: Optional[bool] = None,
172
+ cors_allow_headers: Optional[List[str]] = None
172
173
  ) -> Dict[str, Any]:
173
174
  """
174
175
  Get security defaults based on environment and domains.
@@ -178,6 +179,7 @@ class SmartDefaults:
178
179
  environment: Current environment
179
180
  debug: Django DEBUG setting
180
181
  ssl_redirect: Force SSL redirect on/off (None = auto based on domains)
182
+ cors_allow_headers: Additional CORS headers to extend defaults
181
183
 
182
184
  Returns:
183
185
  Security settings dictionary
@@ -185,92 +187,23 @@ class SmartDefaults:
185
187
  try:
186
188
  settings = {}
187
189
 
188
- # CORS settings
189
- if domains:
190
- if environment == "development" or debug:
191
- # Development: Allow all origins for convenience
192
- settings['CORS_ALLOW_ALL_ORIGINS'] = True
193
- settings['CORS_ALLOW_CREDENTIALS'] = True
194
-
195
- # For development, add ALL domains to CSRF trusted origins
196
- # This allows testing with production domains in dev environment
197
- csrf_trusted_origins = []
198
- for domain in domains:
199
- if domain.startswith(('localhost', '127.0.0.1', '0.0.0.0')):
200
- # Local domains: add HTTP with common ports
201
- csrf_trusted_origins.extend([
202
- f"http://{domain}",
203
- f"http://{domain}:8000",
204
- f"http://{domain}:3000",
205
- ])
206
- elif domain.endswith('.local'):
207
- # .local domains: add both HTTP and HTTPS
208
- csrf_trusted_origins.extend([
209
- f"http://{domain}",
210
- f"https://{domain}",
211
- ])
212
- else:
213
- # External domains: add HTTPS for dev testing with production domains
214
- csrf_trusted_origins.extend([
215
- f"https://{domain}",
216
- f"http://{domain}", # Also HTTP for flexibility
217
- ])
218
-
219
- if csrf_trusted_origins:
220
- settings['CSRF_TRUSTED_ORIGINS'] = csrf_trusted_origins
221
- else:
222
- # Production: Restrict to specified domains
223
- allowed_origins = []
224
- csrf_trusted_origins = []
225
-
226
- for domain in domains:
227
- # CORS origins - only add www for root domains
228
- allowed_origins.append(f"https://{domain}")
229
-
230
- # Only add www. for root domains (no subdomains)
231
- if '.' in domain and domain.count('.') == 1:
232
- allowed_origins.append(f"https://www.{domain}")
233
-
234
- # CSRF trusted origins (critical for HTTPS)
235
- csrf_trusted_origins.append(f"https://{domain}")
236
-
237
- # Only add www. for root domains (no subdomains)
238
- if '.' in domain and domain.count('.') == 1:
239
- csrf_trusted_origins.append(f"https://www.{domain}")
240
-
241
- settings['CORS_ALLOWED_ORIGINS'] = allowed_origins
242
- settings['CORS_ALLOW_CREDENTIALS'] = True
243
-
244
- # Set CSRF trusted origins for HTTPS domains
245
- if csrf_trusted_origins:
246
- settings['CSRF_TRUSTED_ORIGINS'] = csrf_trusted_origins
190
+ if not domains:
191
+ return settings
192
+
193
+ is_dev = environment == "development" or debug
247
194
 
248
- # Security headers for production
195
+ # Generate CORS settings
196
+ cors_settings = cls._generate_cors_settings(domains, is_dev, cors_allow_headers)
197
+ settings.update(cors_settings)
198
+
199
+ # Generate CSRF trusted origins
200
+ csrf_settings = cls._generate_csrf_settings(domains, is_dev)
201
+ settings.update(csrf_settings)
202
+
203
+ # Generate security headers for production
249
204
  if environment == "production":
250
- settings.update({
251
- 'SECURE_BROWSER_XSS_FILTER': True,
252
- 'SECURE_CONTENT_TYPE_NOSNIFF': True,
253
- 'SECURE_HSTS_SECONDS': 31536000, # 1 year
254
- 'SECURE_HSTS_INCLUDE_SUBDOMAINS': True,
255
- 'SECURE_HSTS_PRELOAD': True,
256
- 'X_FRAME_OPTIONS': 'DENY',
257
- })
258
-
259
- # SSL settings - configurable or auto-detect based on domains
260
- should_use_ssl = ssl_redirect if ssl_redirect is not None else bool(domains)
261
- if should_use_ssl:
262
- settings.update({
263
- 'SECURE_SSL_REDIRECT': True,
264
- 'SESSION_COOKIE_SECURE': True,
265
- 'CSRF_COOKIE_SECURE': True,
266
- })
267
- elif ssl_redirect is False:
268
- # Explicitly disable SSL redirect
269
- settings.update({
270
- 'SECURE_SSL_REDIRECT': False,
271
- 'SESSION_COOKIE_SECURE': False,
272
- 'CSRF_COOKIE_SECURE': False,
273
- })
205
+ security_headers = cls._generate_security_headers(domains, ssl_redirect)
206
+ settings.update(security_headers)
274
207
 
275
208
  return settings
276
209
 
@@ -284,6 +217,199 @@ class SmartDefaults:
284
217
  }
285
218
  ) from e
286
219
 
220
+ @classmethod
221
+ def _generate_cors_settings(
222
+ cls,
223
+ domains: List[str],
224
+ is_dev: bool,
225
+ cors_allow_headers: Optional[List[str]] = None
226
+ ) -> Dict[str, Any]:
227
+ """Generate CORS-specific settings."""
228
+ settings = {
229
+ 'CORS_ALLOW_CREDENTIALS': True,
230
+ 'CORS_ALLOW_HEADERS': cls._get_cors_headers(cors_allow_headers)
231
+ }
232
+
233
+ if is_dev:
234
+ # Development: Allow all origins for convenience
235
+ settings['CORS_ALLOW_ALL_ORIGINS'] = True
236
+ else:
237
+ # Production: Restrict to specified domains
238
+ settings['CORS_ALLOWED_ORIGINS'] = cls._build_allowed_origins(domains)
239
+
240
+ return settings
241
+
242
+ @classmethod
243
+ def _generate_csrf_settings(cls, domains: List[str], is_dev: bool) -> Dict[str, Any]:
244
+ """Generate CSRF trusted origins."""
245
+ if is_dev:
246
+ csrf_origins = cls._build_dev_csrf_origins(domains)
247
+ else:
248
+ csrf_origins = cls._build_prod_csrf_origins(domains)
249
+
250
+ # Only return CSRF settings if we have origins to set
251
+ if csrf_origins:
252
+ return {'CSRF_TRUSTED_ORIGINS': csrf_origins}
253
+
254
+ return {}
255
+
256
+ @classmethod
257
+ def _generate_security_headers(
258
+ cls,
259
+ domains: List[str],
260
+ ssl_redirect: Optional[bool] = None
261
+ ) -> Dict[str, Any]:
262
+ """Generate security headers for production."""
263
+ settings = {
264
+ 'SECURE_BROWSER_XSS_FILTER': True,
265
+ 'SECURE_CONTENT_TYPE_NOSNIFF': True,
266
+ 'SECURE_HSTS_SECONDS': 31536000, # 1 year
267
+ 'SECURE_HSTS_INCLUDE_SUBDOMAINS': True,
268
+ 'SECURE_HSTS_PRELOAD': True,
269
+ 'X_FRAME_OPTIONS': 'DENY',
270
+ }
271
+
272
+ # SSL settings - configurable or auto-detect based on domains
273
+ should_use_ssl = ssl_redirect if ssl_redirect is not None else bool(domains)
274
+
275
+ if should_use_ssl:
276
+ settings.update({
277
+ 'SECURE_SSL_REDIRECT': True,
278
+ 'SESSION_COOKIE_SECURE': True,
279
+ 'CSRF_COOKIE_SECURE': True,
280
+ })
281
+ elif ssl_redirect is False:
282
+ # Explicitly disable SSL redirect
283
+ settings.update({
284
+ 'SECURE_SSL_REDIRECT': False,
285
+ 'SESSION_COOKIE_SECURE': False,
286
+ 'CSRF_COOKIE_SECURE': False,
287
+ })
288
+
289
+ return settings
290
+
291
+ @classmethod
292
+ def _get_cors_headers(cls, cors_allow_headers: Optional[List[str]] = None) -> List[str]:
293
+ """
294
+ Get CORS headers with defaults extended by custom headers.
295
+
296
+ Note: The default headers are defined in DjangoConfig.cors_allow_headers.
297
+ This method should be consistent with those defaults.
298
+ """
299
+ # Default headers - should match DjangoConfig.cors_allow_headers defaults
300
+ default_headers = [
301
+ "accept",
302
+ "accept-encoding",
303
+ "authorization",
304
+ "content-type",
305
+ "dnt",
306
+ "origin",
307
+ "user-agent",
308
+ "x-csrftoken",
309
+ "x-requested-with",
310
+ "x-api-key",
311
+ "x-api-token",
312
+ ]
313
+
314
+ if not cors_allow_headers:
315
+ return default_headers
316
+
317
+ # Extend with custom headers and remove duplicates while preserving order
318
+ return cls._merge_headers(default_headers, cors_allow_headers)
319
+
320
+ @classmethod
321
+ def _merge_headers(cls, default_headers: List[str], custom_headers: List[str]) -> List[str]:
322
+ """Merge header lists removing duplicates while preserving order."""
323
+ all_headers = default_headers + custom_headers
324
+ seen = set()
325
+ unique_headers = []
326
+
327
+ for header in all_headers:
328
+ header_lower = header.lower()
329
+ if header_lower not in seen:
330
+ seen.add(header_lower)
331
+ unique_headers.append(header)
332
+
333
+ return unique_headers
334
+
335
+ @classmethod
336
+ def _build_allowed_origins(cls, domains: List[str]) -> List[str]:
337
+ """Build CORS allowed origins for production."""
338
+ allowed_origins = []
339
+
340
+ for domain in domains:
341
+ # Add HTTPS version
342
+ allowed_origins.append(f"https://{domain}")
343
+
344
+ # Add www. version if applicable
345
+ if cls._should_add_www_variant(domain):
346
+ allowed_origins.append(f"https://www.{domain}")
347
+
348
+ return allowed_origins
349
+
350
+ @classmethod
351
+ def _build_dev_csrf_origins(cls, domains: List[str]) -> List[str]:
352
+ """Build CSRF trusted origins for development."""
353
+ csrf_origins = []
354
+
355
+ for domain in domains:
356
+ if domain.startswith(('localhost', '127.0.0.1', '0.0.0.0')):
357
+ # Local domains: add HTTP with common ports
358
+ csrf_origins.extend([
359
+ f"http://{domain}",
360
+ f"http://{domain}:8000",
361
+ f"http://{domain}:3000",
362
+ ])
363
+ elif domain.endswith('.local'):
364
+ # .local domains: add both HTTP and HTTPS
365
+ csrf_origins.extend([
366
+ f"http://{domain}",
367
+ f"https://{domain}",
368
+ ])
369
+ else:
370
+ # External domains: add both for dev flexibility
371
+ csrf_origins.extend([
372
+ f"https://{domain}",
373
+ f"http://{domain}",
374
+ ])
375
+
376
+ return csrf_origins
377
+
378
+ @classmethod
379
+ def _build_prod_csrf_origins(cls, domains: List[str]) -> List[str]:
380
+ """Build CSRF trusted origins for production."""
381
+ csrf_origins = []
382
+
383
+ for domain in domains:
384
+ # Add HTTPS version
385
+ csrf_origins.append(f"https://{domain}")
386
+
387
+ # Add www. version if applicable
388
+ if cls._should_add_www_variant(domain):
389
+ csrf_origins.append(f"https://www.{domain}")
390
+
391
+ return csrf_origins
392
+
393
+ @classmethod
394
+ def _should_add_www_variant(cls, domain: str) -> bool:
395
+ """
396
+ Check if domain should get a www. variant added.
397
+
398
+ Simple rule: add www. variant only if domain doesn't already start with www.
399
+ Let users handle complex subdomain logic themselves by providing exact domains they want.
400
+
401
+ Examples:
402
+ - example.com -> True (add www.example.com)
403
+ - www.example.com -> False (already has www)
404
+ - api.example.com -> True (add www.api.example.com - let user decide)
405
+ - localhost -> False (no dot)
406
+ """
407
+ if not domain or '.' not in domain:
408
+ return False
409
+
410
+ # Don't add www if domain already starts with www
411
+ return not domain.startswith('www.')
412
+
287
413
  @classmethod
288
414
  def get_database_defaults(
289
415
  cls,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-cfg
3
- Version: 1.2.20
3
+ Version: 1.2.22
4
4
  Summary: 🚀 Next-gen Django configuration: type-safety, AI features, blazing-fast setup, and automated best practices — all in one.
5
5
  Project-URL: Homepage, https://djangocfg.com
6
6
  Project-URL: Documentation, https://docs.djangocfg.com
@@ -1,5 +1,5 @@
1
1
  django_cfg/README.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- django_cfg/__init__.py,sha256=VOs7_35T5Qyz-XoqBFSELRGIybr1aoFgOIkYvoZU61g,1631
2
+ django_cfg/__init__.py,sha256=Xr1TpxIGCz8PGP-3n7OZqU3lCSjl9yNS4gakIXX7gqo,1631
3
3
  django_cfg/apps.py,sha256=k84brkeXJI7EgKZLEpTkM9YFZofKI4PzhFOn1cl9Msc,1656
4
4
  django_cfg/config.py,sha256=ME-JKaVzcdmaGhuc1YTkEWoMKSaUasNf1SBlNz-NfrM,1399
5
5
  django_cfg/urls.py,sha256=bpRFjMonQuk4UCUMxx4ueBX3YDNB7HXKFwEghQ3KR3o,793
@@ -214,7 +214,7 @@ django_cfg/apps/maintenance/admin/__init__.py,sha256=TqusqIrLX50xapmtOALAkJ0hN-9
214
214
  django_cfg/apps/maintenance/admin/api_key_admin.py,sha256=l6LiLlw3M64tVssq1PFlmvahLYiq1VS-jHYJdZMrCus,5990
215
215
  django_cfg/apps/maintenance/admin/log_admin.py,sha256=x0zAYGUXTckH2eS7wjW7bbGHSWlwqq1-jRz_UmSCoEI,4814
216
216
  django_cfg/apps/maintenance/admin/scheduled_admin.py,sha256=Tbkah4TB0mLNLe4uZLMhYDULKRA6mnTiS3Dm6-2SaYA,14957
217
- django_cfg/apps/maintenance/admin/site_admin.py,sha256=LAkUpcVWj6GUVtJP2jKA96YNIi9SCBSj49TRzPXBlR4,16216
217
+ django_cfg/apps/maintenance/admin/site_admin.py,sha256=MMiDsO7-_t4yTYtPTnpe6GZ2zCY07xMOebKKA2D59OQ,17714
218
218
  django_cfg/apps/maintenance/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
219
219
  django_cfg/apps/maintenance/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
220
220
  django_cfg/apps/maintenance/management/commands/maintenance.py,sha256=I7ZpQEELSEC-itzK0U6G7HVrdtmpfHSN6ByTv4dc9pg,11557
@@ -225,17 +225,18 @@ django_cfg/apps/maintenance/managers/cloudflare_site_manager.py,sha256=Mr8_2u0wS
225
225
  django_cfg/apps/maintenance/managers/maintenance_log_manager.py,sha256=SEbEIy6yEWDHVtQAJE1fixU1nOown6ONPbWngKv878w,4736
226
226
  django_cfg/apps/maintenance/migrations/0001_initial.py,sha256=_TY5VA_f_ozqRRhAGADiuuU6Gd1GmM5JzOTWiEgVeFE,14757
227
227
  django_cfg/apps/maintenance/migrations/0002_cloudflaresite_maintenance_url.py,sha256=6-xOC2hsn2_TdrtB8k7wkrYJX4l3Vn6m780glGxNBHg,566
228
+ django_cfg/apps/maintenance/migrations/0003_cloudflaresite_include_subdomains_and_more.py,sha256=uxhMhI9tEUjoZqbaOGRNM1Hu1hyYK1dI1kiVxytD2bM,820
228
229
  django_cfg/apps/maintenance/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
229
230
  django_cfg/apps/maintenance/models/__init__.py,sha256=z8FpMPCBLAp8Ose2_fPSYhrbuHSI7tAtRbADwhd_hu4,1074
230
231
  django_cfg/apps/maintenance/models/cloudflare_api_key.py,sha256=B5pkZD9Gu_Z1XXek2VY-7SdeH0ZnXK5cKhxnaCWcv2k,3366
231
- django_cfg/apps/maintenance/models/cloudflare_site.py,sha256=YirWNZ63buvMAqHEFeC7Vc4vh7ukI5iHOdrE7XaJ5Mg,4030
232
+ django_cfg/apps/maintenance/models/cloudflare_site.py,sha256=tMeaMSk4z-_NnxYbzrkjEwMkVGkfPm4TSgaZ0pLoRc8,5708
232
233
  django_cfg/apps/maintenance/models/maintenance_log.py,sha256=icqjQf37-EsjHWq8MsdgHHyuMNalH84R8f_z-BKIA2M,3922
233
234
  django_cfg/apps/maintenance/models/scheduled_maintenance.py,sha256=J8-8efqZsZh2FQoW3b1MtXcNeuWWr7UkScRUL_YdbGg,10368
234
235
  django_cfg/apps/maintenance/services/__init__.py,sha256=KdMiqVBVecJVzCh76j5ImRHa5qOLbZsyqY4ITmaCd0c,2584
235
236
  django_cfg/apps/maintenance/services/bulk_operations_service.py,sha256=O3FCYhIuSNW7PE-86aBmA7nxPtbflye9Qv3WCgQ9s-A,15039
236
- django_cfg/apps/maintenance/services/maintenance_service.py,sha256=MiHnDcTNAik-CWOJ_XWPsv14BZmUqVwQ46TUd6YrUzM,8641
237
+ django_cfg/apps/maintenance/services/maintenance_service.py,sha256=oloMxhG2Ht6BQnMT3DNy1GQXfb1K9DqLdOeuQp42pV4,12830
237
238
  django_cfg/apps/maintenance/services/scheduled_maintenance_service.py,sha256=X9xP13B7OPUcMsl8G_U5zUPmni7pO2ru8osASCiZcfE,15218
238
- django_cfg/apps/maintenance/services/site_sync_service.py,sha256=F4k2NFz6dQp_sgyglFQUwyVItl_eC27uBXwLVt-5V7w,13712
239
+ django_cfg/apps/maintenance/services/site_sync_service.py,sha256=ljtvGfq1eDqlegKjcbR9JeqsBGzpCONoNYBmwFzZNZk,15737
239
240
  django_cfg/apps/maintenance/utils/__init__.py,sha256=L6UhtM9MoN1L26-l9C_Nyjp8-S-EB5_VvtvcX_E0isc,221
240
241
  django_cfg/apps/maintenance/utils/retry_utils.py,sha256=O55jtdDf9om_QOf9rIAFt7ZEUeE5Ttq-KRLmSA9Bkps,4091
241
242
  django_cfg/apps/newsletter/README.md,sha256=cnNXnAUsCVtelMNGYc4a8qJsoiVb--J2OOSh_Jw8piA,3202
@@ -245,7 +246,7 @@ django_cfg/apps/newsletter/admin_filters.py,sha256=lPMtHULDOisTsN9_2BMoGu23ICkFE
245
246
  django_cfg/apps/newsletter/apps.py,sha256=TXrULqE2HbmEIHaLomw7z9bkC19le1rKwlUWhK1xrVo,566
246
247
  django_cfg/apps/newsletter/models.py,sha256=tc5IEUJZUAdYbQOhT_XvfiGL86FIb5LvPAuq7TOPrAM,8930
247
248
  django_cfg/apps/newsletter/serializers.py,sha256=Nse8ZmBDNdhzfgZu53LNp_JOR327rI1fSHpgdJtCoV8,4133
248
- django_cfg/apps/newsletter/signals.py,sha256=0wkOxEXnwBnLA1B72sZ_nb_x2ycsvQSQ3jvMwYi92zk,2974
249
+ django_cfg/apps/newsletter/signals.py,sha256=kbjSvnMIy4kwmE_r02YFMneCrHy0oRuc_spjki976dM,3003
249
250
  django_cfg/apps/newsletter/urls.py,sha256=Zfbgj0NZ06dMu503JOn4GGgmKpQ3tOjTIyUmEslaJdE,1609
250
251
  django_cfg/apps/newsletter/admin/__init__.py,sha256=dXCym_3qp9HxT0sUV_LBGgEkKv1k_Mj3a0TTZYnH2yI,290
251
252
  django_cfg/apps/newsletter/admin/filters.py,sha256=lPMtHULDOisTsN9_2BMoGu23ICkFEJDZst5Fhj5Sv5c,3675
@@ -266,6 +267,47 @@ django_cfg/apps/newsletter/views/emails.py,sha256=w-W_egdfFbsbgfW8WjqT0DBJl596lJ
266
267
  django_cfg/apps/newsletter/views/newsletters.py,sha256=gb8skjDYxHd8R2DAVUhSe6z4lnKDCS_e9zbyyHok4CI,1370
267
268
  django_cfg/apps/newsletter/views/subscriptions.py,sha256=marHLbRT6a6e8tMjKVtKG_0K6G_gcjKCU9LmMGihKwg,4774
268
269
  django_cfg/apps/newsletter/views/tracking.py,sha256=EJlAltpASzc_0nslVPJt-6mnIqI_QCEmz3MQEGPKzmU,2481
270
+ django_cfg/apps/payments/__init__.py,sha256=Qb8viLJBKCclV9uuoXjxWXeDevXlbdJ76mV8g5hK7tk,237
271
+ django_cfg/apps/payments/apps.py,sha256=FZgbLQFMeOJPs_892bM6X-3Edt3YPD2CP50HMekH7Sk,551
272
+ django_cfg/apps/payments/urls.py,sha256=aJ4hC3quZvn1c_JJHVWd305DLFAHhtkBHGS-i7XfYCw,3508
273
+ django_cfg/apps/payments/managers/__init__.py,sha256=uYiETCw-K5GXQyAwpcOa2Qxzof8sbtTNc_SghyW45YU,672
274
+ django_cfg/apps/payments/managers/api_key_manager.py,sha256=xhViRKCLC_eR68hankMZQTcbzMgiRJdyr8KYKk01_dQ,928
275
+ django_cfg/apps/payments/managers/balance_manager.py,sha256=Sm_EETlHO7LtlrWIqF65vFPS4FpPSNYo5oTgQwTFAZ4,13279
276
+ django_cfg/apps/payments/managers/currency_manager.py,sha256=-iq_Nhd3cj_n1aUzObBIMhRRHtpOv50Z0phdwOcKv6w,876
277
+ django_cfg/apps/payments/managers/payment_manager.py,sha256=udiTFIIVXsjqmlwzFwcT0ZTkYJZ9HVOSLLFTvAodY3w,1467
278
+ django_cfg/apps/payments/managers/subscription_manager.py,sha256=LHrw5INc1nSqfpw76bn7W2poEA-29FXfF5uhaxmq7l8,968
279
+ django_cfg/apps/payments/managers/tariff_manager.py,sha256=Kor_0ApvROcH0UKlp1-9rYChtHWDeOFgUc1GG3IepxY,799
280
+ django_cfg/apps/payments/middleware/__init__.py,sha256=ryn3emWBq15-kE8eJxX19gd-eTrk7JlpXqV2Cg8N_Wg,294
281
+ django_cfg/apps/payments/migrations/0001_initial.py,sha256=u4as4J5YycFDAs4acQz9girjg2Hp9uTn8Hy7WZEUI6U,39911
282
+ django_cfg/apps/payments/migrations/__init__.py,sha256=OHlzxEGDJYKZz82orZXnh77xy-Okv6FcG3EKMfg9LzU,21
283
+ django_cfg/apps/payments/models/__init__.py,sha256=UV1xEm1osEkWA5XmvBJSS5YU2fddqkvSum6-_15IBH0,882
284
+ django_cfg/apps/payments/models/api_keys.py,sha256=6V9hOSPQT27qEWaygWrtmQPqCeZpgHZv1KAfsgXnS-Q,2476
285
+ django_cfg/apps/payments/models/balance.py,sha256=wn63yjOVIbLbirAjKLAZm03ooXeOe3yOqDGVr_hiLZY,7026
286
+ django_cfg/apps/payments/models/base.py,sha256=T8mQKFXlpLc05xZDmSdOfrOAc8s_mGnKqoSgEhaY9Kk,349
287
+ django_cfg/apps/payments/models/currencies.py,sha256=lz6axNRmfoQa3od-EV78vbZQv3vh2FznxHzGBi20qIU,4106
288
+ django_cfg/apps/payments/models/events.py,sha256=xIrAj8nyBq0NTc0YA-SolJSxG9Mr3ut4gyARsY-QMRM,2364
289
+ django_cfg/apps/payments/models/payments.py,sha256=7CLgRFWPg8K5ajjXjG5_xy8wpACzTAMxOzOufbyIaAI,9540
290
+ django_cfg/apps/payments/models/subscriptions.py,sha256=RuINi31j2DIhI_V_-HNvhdq8qa-woAGrUDeWOJOq3so,8167
291
+ django_cfg/apps/payments/models/tariffs.py,sha256=nqM3RPtu4itAHRvT6jAgZgQEdEIN1KgKnEljkaHGFDc,2749
292
+ django_cfg/apps/payments/serializers/__init__.py,sha256=4l7Tu1NXztXtqceVbC3OxtWJir4n3_dFpVEgRgQ9J4k,1416
293
+ django_cfg/apps/payments/serializers/api_keys.py,sha256=5qG3PEwIVfoNSC6XpbOBbC3l4umgld3kPJC5l_vsYV0,1396
294
+ django_cfg/apps/payments/serializers/balance.py,sha256=QzR1MTRQ_4uTJBRefRB6X-z-0QOkOuHmCyNTojYj_8w,2025
295
+ django_cfg/apps/payments/serializers/currencies.py,sha256=SskSl3rjZBxxLnY_zsaJiFCGfbkz9WyWFHLHiJbbTIM,1821
296
+ django_cfg/apps/payments/serializers/payments.py,sha256=BDhcD9DCea50Cz1PumLNVntgH40dOR55NzCXv4I0YOQ,2258
297
+ django_cfg/apps/payments/serializers/subscriptions.py,sha256=16OileC0yxM90ERK3Uo5Jqe9DeyNf3tBwK-ZqDtEbPw,2795
298
+ django_cfg/apps/payments/serializers/tariffs.py,sha256=54N5tFpc5NBIMyXuN7Re6pDNoQLJc2yZBIb5uVRhn-I,1698
299
+ django_cfg/apps/payments/services/__init__.py,sha256=GigyUFB3pT1qpN1uV1-LZUXVQFPMNkbjh6i6sV4iZsw,280
300
+ django_cfg/apps/payments/services/base.py,sha256=2xX42CnTDObNNc0atXwEWpozI1fAbh7Y4uOgBAoHGzY,2302
301
+ django_cfg/apps/payments/services/nowpayments.py,sha256=K31_KFM9KvkKidbbgYBgnIwg7I49dFBTSkD9upyYkO8,2878
302
+ django_cfg/apps/payments/services/providers.py,sha256=7t335fOtBwwqMa_HLpvuJ-dW3Zyi8AjkKApSurhidTY,2337
303
+ django_cfg/apps/payments/services/redis_service.py,sha256=xarjV3ndkuXXTHy0N9yuLfEvcg0it4pNNQ-yghNwIqo,8193
304
+ django_cfg/apps/payments/views/__init__.py,sha256=00HRO1sDErjnFq2dedFAjBIyIhZZyZmv4DK98lHmx2Q,1613
305
+ django_cfg/apps/payments/views/api_key_views.py,sha256=fG68roqOF9FShde68Qp_CBf0KJuf1chwK41RU0VqUJk,5542
306
+ django_cfg/apps/payments/views/balance_views.py,sha256=rA_OJFizP_UBBr8OdWLQZQ51qlPFYoeJCYUzNXSw4S0,2509
307
+ django_cfg/apps/payments/views/currency_views.py,sha256=B1rjOKDV3KEYRQI6NuPEyEGF8VNumaraoZdI8Qqdu6s,4096
308
+ django_cfg/apps/payments/views/payment_views.py,sha256=zfdHiHJhGby6KHpTe5S9UVeC-pFrJD-RTMhHhkSCl5s,4122
309
+ django_cfg/apps/payments/views/subscription_views.py,sha256=WqBDsaPUQGP6ZCmbheIdRupy-qESPpdj8IgKkaLp3V8,5005
310
+ django_cfg/apps/payments/views/tariff_views.py,sha256=i0uOg6SBk_1sct2M2iwKMw-5YHMr5mhVvm_ljpFRwPQ,4907
269
311
  django_cfg/apps/support/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
270
312
  django_cfg/apps/support/admin.py,sha256=-fcegtqoCcwPiBXwyNLMftcYCTTbTRRBpWItyeNNkDY,8827
271
313
  django_cfg/apps/support/admin_filters.py,sha256=ZpKtetRxppRAMwIr-pwDbXAyh7qouDfTCEZoo1YJfFs,2179
@@ -323,16 +365,16 @@ django_cfg/cli/commands/__init__.py,sha256=EKLXDAx-QttnGmdjsmVANAfhxWplxl2V_2I0S
323
365
  django_cfg/cli/commands/create_project.py,sha256=iuf965j8Yg7zxHcPb0GtFHEj73CYXC45ZJRmd6RbA9E,21025
324
366
  django_cfg/cli/commands/info.py,sha256=o4S1xPJSHv2oEVqmH0X9RTF5f-8Wy9579yHkyd_PC3E,4923
325
367
  django_cfg/core/__init__.py,sha256=eVK57qFOok9kTeHoNEMQ1BplkUOaQ7NB9kP9eQK1vg0,358
326
- django_cfg/core/config.py,sha256=Khn4-yrivGkovH06uUJ3_uen8lt3I54XMKT5lYk5l3Y,27636
368
+ django_cfg/core/config.py,sha256=TS78BFOtzaErZMdEQgZvY2cnMq5PGaC74rOR8dttRuY,28404
327
369
  django_cfg/core/environment.py,sha256=MAoEPqIPsLVhSANT2Bz4nnus2wmbMW0RCOQxhQfDrDc,9106
328
370
  django_cfg/core/exceptions.py,sha256=RTQEoU3PfR8lqqNNv5ayd_HY2yJLs3eioqUy8VM6AG4,10378
329
- django_cfg/core/generation.py,sha256=zq6QZRyE8vS_fZVk2SbqHsCC_43DSvAUU4T1pMf8gSs,25374
371
+ django_cfg/core/generation.py,sha256=Oa9bnEPsxwEaa0RP71zNl_z2p9NNljHnoCTeRu72X-0,25421
330
372
  django_cfg/core/integration.py,sha256=5kzkZSd45ij0rfrBdeNUYnDalObqvK__XpoP31xFYKo,5224
331
373
  django_cfg/core/validation.py,sha256=PhwDBTs24nuM3xqfIT3hXmN88VrhMT-Bk8Yb8FxjmPk,6590
332
374
  django_cfg/management/__init__.py,sha256=NrLAhiS59hqjy-bipOC1abNuRiNm5BpKXmjN05VzKbM,28
333
375
  django_cfg/management/commands/__init__.py,sha256=wc5DFEklUo-wB-6VAAmsV5UTbo5s3t936Lu61z4lojs,29
334
376
  django_cfg/management/commands/auto_generate.py,sha256=N5IiWYV5claV6gq2rMPB1UMgkH9GK-2gNtbX0IDy754,14195
335
- django_cfg/management/commands/check_settings.py,sha256=5dtYecXD1GEKGABDmZZBNp6NbBXAbasGwltOwe2GOaA,8757
377
+ django_cfg/management/commands/check_settings.py,sha256=JyVhL4dLnFTXkkMMpSnLoibZ8mfOMPOJ6RXAcESg-74,11509
336
378
  django_cfg/management/commands/clear_constance.py,sha256=bSUhxEIKFLmXVilQGn3s9FZuldqDxDq9P9LmybZns_w,8043
337
379
  django_cfg/management/commands/create_token.py,sha256=beHtUTuyFZhG97F9vSkaX-u7tieAZW-C6pntujGw1C8,11796
338
380
  django_cfg/management/commands/generate.py,sha256=w0BF7IMftxNjxTxFuY8cw5pNKGW-LmTScJ8kZpxHu_8,4248
@@ -372,12 +414,12 @@ django_cfg/models/jwt.py,sha256=3R_dpLmVZIcH4zdtwA4qKnuCB8RZQACrgsbbgWY2q4c,9025
372
414
  django_cfg/models/limits.py,sha256=nUfvyPykwKR38ZOlIFqlNGRmfV8RO5hiUrhDH6FCHJw,7449
373
415
  django_cfg/models/logging.py,sha256=4vZF-G9rPmXMxxtUx_ad7Esvgbe8a_5Dl692Yg0fL4A,10636
374
416
  django_cfg/models/ngrok.py,sha256=MVgcKWx0DRSW0QcwhiSx2vVwTSG49vbVrzPkZqDK-zw,3575
375
- django_cfg/models/revolution.py,sha256=n8CLLniMac9PTV5KDcfoO-_8F6U40jLT3DU8-kIIZ4I,7543
417
+ django_cfg/models/revolution.py,sha256=7Rj-EYvNK4EEttMqtE95ejLWzvucz8rFelWNBNTKk3s,8130
376
418
  django_cfg/models/security.py,sha256=Xv19ZVOIenB_-f0wB6fm-Ap4j9kA43bSFaT2XenpSqc,4685
377
419
  django_cfg/models/services.py,sha256=fj9JjrJFrlL4DMnMbx_D8JiiZpz4E5uBqmhquAxau7c,13159
378
420
  django_cfg/models/tasks.py,sha256=2T3apcUFf8zevYJmapbFrh6bWv5PTJPeXR6Bc5vlj4c,15524
379
421
  django_cfg/modules/__init__.py,sha256=Ip9WMpzImEwIAywpFwU056_v0O9oIGG7nCT1YSArxkw,316
380
- django_cfg/modules/base.py,sha256=A-pWUckGKrCAlgfnCfkKmjwtgZjyhc_z-hvJ4ogocpI,5474
422
+ django_cfg/modules/base.py,sha256=_agj4rt9CrEfrDVL29A1vgFYIwZXXg6Wf7aCNFFdXo0,5732
381
423
  django_cfg/modules/django_email.py,sha256=2XXlIKzD6Jao3CT4_zIE2eaM9Cc9ROA1tjp2bJ9z5Lo,16592
382
424
  django_cfg/modules/django_health.py,sha256=7QzuQ6WyjWYj6lecd4auwRvEyrMUL7N6hiAp-tLyoY4,8923
383
425
  django_cfg/modules/django_logger.py,sha256=3oP9jev0lOcFUJ1tYcpbFnK524zIGA2xIOrrAiTwpb8,6331
@@ -499,11 +541,11 @@ django_cfg/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
499
541
  django_cfg/templatetags/django_cfg.py,sha256=11_3YX0jAVuOd_fVcDixAxyDMG4V7A98SPqv8Lbfpxc,1308
500
542
  django_cfg/utils/__init__.py,sha256=64wwXJuXytvwt8Ze_erSR2HmV07nGWJ6DV5wloRBvYE,435
501
543
  django_cfg/utils/path_resolution.py,sha256=C9As6p4Q9l3VeoVkFDRPQWGrzAWf8O8UxLVkaI3ToVM,13899
502
- django_cfg/utils/smart_defaults.py,sha256=b6A1z7VO1NJGq0oUQXN5P97c3k_Ssgw6qUi0mK-4TlM,19786
544
+ django_cfg/utils/smart_defaults.py,sha256=MxbUZwn_xbh48li7uLI6W4D9WCD2P2WO48dv85Fra5E,23057
503
545
  django_cfg/utils/toolkit.py,sha256=Td8_iXNaftonF_xdZP4Y3uO65nuA_4_zditn5Q_Pfcw,23310
504
546
  django_cfg/utils/version_check.py,sha256=jI4v3YMdQriUEeb_TvRl511sDghy6I75iKRDUaNpucs,4800
505
- django_cfg-1.2.20.dist-info/METADATA,sha256=eTO1rvtvACRkkXDfByIoTkYjZvam54MMtG4NLzwO-J4,38434
506
- django_cfg-1.2.20.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
507
- django_cfg-1.2.20.dist-info/entry_points.txt,sha256=Ucmde4Z2wEzgb4AggxxZ0zaYDb9HpyE5blM3uJ0_VNg,56
508
- django_cfg-1.2.20.dist-info/licenses/LICENSE,sha256=xHuytiUkSZCRG3N11nk1X6q1_EGQtv6aL5O9cqNRhKE,1071
509
- django_cfg-1.2.20.dist-info/RECORD,,
547
+ django_cfg-1.2.22.dist-info/METADATA,sha256=VGD-7Y0LSzV1UdNyMYvkZ2w8WIO14V_uk1T0Xe0WbIg,38434
548
+ django_cfg-1.2.22.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
549
+ django_cfg-1.2.22.dist-info/entry_points.txt,sha256=Ucmde4Z2wEzgb4AggxxZ0zaYDb9HpyE5blM3uJ0_VNg,56
550
+ django_cfg-1.2.22.dist-info/licenses/LICENSE,sha256=xHuytiUkSZCRG3N11nk1X6q1_EGQtv6aL5O9cqNRhKE,1071
551
+ django_cfg-1.2.22.dist-info/RECORD,,