django-cfg 1.2.31__py3-none-any.whl → 1.3.1__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_cfg/__init__.py +1 -1
- django_cfg/apps/api/health/views.py +4 -2
- django_cfg/apps/knowbase/config/settings.py +16 -15
- django_cfg/apps/payments/README.md +326 -0
- django_cfg/apps/payments/admin/__init__.py +20 -10
- django_cfg/apps/payments/admin/api_keys_admin.py +521 -237
- django_cfg/apps/payments/admin/balance_admin.py +592 -297
- django_cfg/apps/payments/admin/currencies_admin.py +526 -222
- django_cfg/apps/payments/admin/filters.py +306 -199
- django_cfg/apps/payments/admin/payments_admin.py +465 -70
- django_cfg/apps/payments/admin/subscriptions_admin.py +578 -128
- django_cfg/apps/payments/admin_interface/__init__.py +18 -0
- django_cfg/apps/payments/admin_interface/templates/payments/base.html +162 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/dev_tool_card.html +38 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/loading_spinner.html +16 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/notification.html +27 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/provider_card.html +86 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_card.html +39 -0
- django_cfg/apps/payments/admin_interface/templates/payments/currency_converter.html +382 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_dashboard.html +300 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +303 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_list.html +382 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_status.html +500 -0
- django_cfg/apps/payments/admin_interface/templates/payments/webhook_dashboard.html +594 -0
- django_cfg/apps/payments/admin_interface/views/__init__.py +23 -0
- django_cfg/apps/payments/admin_interface/views/payment_views.py +259 -0
- django_cfg/apps/payments/admin_interface/views/webhook_dashboard.py +37 -0
- django_cfg/apps/payments/apps.py +34 -9
- django_cfg/apps/payments/config/__init__.py +28 -51
- django_cfg/apps/payments/config/constance/__init__.py +22 -0
- django_cfg/apps/payments/config/constance/config_service.py +123 -0
- django_cfg/apps/payments/config/constance/fields.py +69 -0
- django_cfg/apps/payments/config/constance/settings.py +160 -0
- django_cfg/apps/payments/config/django_cfg_integration.py +202 -0
- django_cfg/apps/payments/config/helpers.py +130 -0
- django_cfg/apps/payments/management/__init__.py +1 -3
- django_cfg/apps/payments/management/commands/__init__.py +1 -3
- django_cfg/apps/payments/management/commands/manage_currencies.py +303 -151
- django_cfg/apps/payments/management/commands/manage_providers.py +333 -160
- django_cfg/apps/payments/middleware/__init__.py +3 -1
- django_cfg/apps/payments/middleware/api_access.py +329 -222
- django_cfg/apps/payments/middleware/rate_limiting.py +342 -152
- django_cfg/apps/payments/middleware/usage_tracking.py +249 -240
- django_cfg/apps/payments/migrations/0001_initial.py +708 -536
- django_cfg/apps/payments/models/__init__.py +13 -18
- django_cfg/apps/payments/models/api_keys.py +121 -43
- django_cfg/apps/payments/models/balance.py +150 -115
- django_cfg/apps/payments/models/base.py +68 -15
- django_cfg/apps/payments/models/currencies.py +172 -148
- django_cfg/apps/payments/models/managers/__init__.py +44 -0
- django_cfg/apps/payments/models/managers/api_key_managers.py +329 -0
- django_cfg/apps/payments/models/managers/balance_managers.py +599 -0
- django_cfg/apps/payments/models/managers/currency_managers.py +385 -0
- django_cfg/apps/payments/models/managers/payment_managers.py +511 -0
- django_cfg/apps/payments/models/managers/subscription_managers.py +641 -0
- django_cfg/apps/payments/models/payments.py +235 -285
- django_cfg/apps/payments/models/subscriptions.py +257 -177
- django_cfg/apps/payments/models/tariffs.py +147 -40
- django_cfg/apps/payments/services/__init__.py +209 -56
- django_cfg/apps/payments/services/cache/__init__.py +6 -6
- django_cfg/apps/payments/services/cache/{simple_cache.py → cache_service.py} +112 -12
- django_cfg/apps/payments/services/core/__init__.py +10 -6
- django_cfg/apps/payments/services/core/balance_service.py +435 -360
- django_cfg/apps/payments/services/core/base.py +166 -0
- django_cfg/apps/payments/services/core/currency_service.py +478 -0
- django_cfg/apps/payments/services/core/payment_service.py +346 -467
- django_cfg/apps/payments/services/core/subscription_service.py +425 -481
- django_cfg/apps/payments/services/core/webhook_service.py +410 -0
- django_cfg/apps/payments/services/integrations/__init__.py +29 -0
- django_cfg/apps/payments/services/integrations/ngrok_service.py +47 -0
- django_cfg/apps/payments/services/integrations/providers_config.py +107 -0
- django_cfg/apps/payments/services/providers/__init__.py +9 -14
- django_cfg/apps/payments/services/providers/base.py +234 -174
- django_cfg/apps/payments/services/providers/nowpayments.py +478 -0
- django_cfg/apps/payments/services/providers/registry.py +367 -301
- django_cfg/apps/payments/services/types/__init__.py +78 -0
- django_cfg/apps/payments/services/types/data.py +177 -0
- django_cfg/apps/payments/services/types/requests.py +150 -0
- django_cfg/apps/payments/services/types/responses.py +156 -0
- django_cfg/apps/payments/services/types/webhooks.py +232 -0
- django_cfg/apps/payments/signals/__init__.py +33 -8
- django_cfg/apps/payments/signals/api_key_signals.py +210 -129
- django_cfg/apps/payments/signals/balance_signals.py +174 -0
- django_cfg/apps/payments/signals/payment_signals.py +128 -103
- django_cfg/apps/payments/signals/subscription_signals.py +194 -142
- django_cfg/apps/payments/static/payments/css/components.css +380 -0
- django_cfg/apps/payments/static/payments/css/dashboard.css +188 -0
- django_cfg/apps/payments/static/payments/js/components.js +545 -0
- django_cfg/apps/payments/static/payments/js/utils.js +412 -0
- django_cfg/apps/payments/templatetags/__init__.py +1 -1
- django_cfg/apps/payments/templatetags/payment_tags.py +466 -0
- django_cfg/apps/payments/urls.py +45 -48
- django_cfg/apps/payments/urls_admin.py +33 -42
- django_cfg/apps/payments/views/api/__init__.py +101 -0
- django_cfg/apps/payments/views/api/api_keys.py +387 -0
- django_cfg/apps/payments/views/api/balances.py +381 -0
- django_cfg/apps/payments/views/api/base.py +298 -0
- django_cfg/apps/payments/views/api/currencies.py +402 -0
- django_cfg/apps/payments/views/api/payments.py +415 -0
- django_cfg/apps/payments/views/api/subscriptions.py +475 -0
- django_cfg/apps/payments/views/api/webhooks.py +476 -0
- django_cfg/apps/payments/views/serializers/__init__.py +99 -0
- django_cfg/apps/payments/views/serializers/api_keys.py +424 -0
- django_cfg/apps/payments/views/serializers/balances.py +300 -0
- django_cfg/apps/payments/views/serializers/currencies.py +335 -0
- django_cfg/apps/payments/views/serializers/payments.py +387 -0
- django_cfg/apps/payments/views/serializers/subscriptions.py +429 -0
- django_cfg/apps/payments/views/serializers/webhooks.py +137 -0
- django_cfg/config.py +1 -1
- django_cfg/core/config.py +40 -4
- django_cfg/core/generation.py +25 -4
- django_cfg/core/integration/README.md +363 -0
- django_cfg/core/integration/__init__.py +47 -0
- django_cfg/core/integration/commands_collector.py +239 -0
- django_cfg/core/integration/display/__init__.py +15 -0
- django_cfg/core/integration/display/base.py +157 -0
- django_cfg/core/integration/display/ngrok.py +164 -0
- django_cfg/core/integration/display/startup.py +815 -0
- django_cfg/core/integration/url_integration.py +123 -0
- django_cfg/core/integration/version_checker.py +160 -0
- django_cfg/management/commands/auto_generate.py +4 -0
- django_cfg/management/commands/check_settings.py +6 -0
- django_cfg/management/commands/clear_constance.py +5 -2
- django_cfg/management/commands/create_token.py +6 -0
- django_cfg/management/commands/list_urls.py +6 -0
- django_cfg/management/commands/migrate_all.py +6 -0
- django_cfg/management/commands/migrator.py +3 -0
- django_cfg/management/commands/rundramatiq.py +6 -0
- django_cfg/management/commands/runserver_ngrok.py +51 -29
- django_cfg/management/commands/script.py +6 -0
- django_cfg/management/commands/show_config.py +12 -2
- django_cfg/management/commands/show_urls.py +4 -0
- django_cfg/management/commands/superuser.py +6 -0
- django_cfg/management/commands/task_clear.py +4 -1
- django_cfg/management/commands/task_status.py +3 -1
- django_cfg/management/commands/test_email.py +3 -0
- django_cfg/management/commands/test_telegram.py +6 -0
- django_cfg/management/commands/test_twilio.py +6 -0
- django_cfg/management/commands/tree.py +6 -0
- django_cfg/management/commands/validate_config.py +155 -149
- django_cfg/models/constance.py +31 -11
- django_cfg/models/payments.py +175 -492
- django_cfg/modules/django_logger.py +160 -146
- django_cfg/modules/django_unfold/dashboard.py +64 -16
- django_cfg/registry/core.py +1 -0
- django_cfg/template_archive/django_sample.zip +0 -0
- django_cfg/utils/smart_defaults.py +222 -571
- django_cfg/utils/toolkit.py +51 -11
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/METADATA +4 -1
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/RECORD +153 -185
- django_cfg/apps/payments/__init__.py +0 -8
- django_cfg/apps/payments/admin/tariffs_admin.py +0 -199
- django_cfg/apps/payments/config/module.py +0 -70
- django_cfg/apps/payments/config/providers.py +0 -105
- django_cfg/apps/payments/config/settings.py +0 -96
- django_cfg/apps/payments/config/utils.py +0 -52
- django_cfg/apps/payments/decorators.py +0 -291
- django_cfg/apps/payments/management/commands/README.md +0 -146
- django_cfg/apps/payments/management/commands/currency_stats.py +0 -304
- django_cfg/apps/payments/managers/__init__.py +0 -23
- django_cfg/apps/payments/managers/api_key_manager.py +0 -35
- django_cfg/apps/payments/managers/balance_manager.py +0 -361
- django_cfg/apps/payments/managers/currency_manager.py +0 -306
- django_cfg/apps/payments/managers/payment_manager.py +0 -192
- django_cfg/apps/payments/managers/subscription_manager.py +0 -37
- django_cfg/apps/payments/managers/tariff_manager.py +0 -29
- django_cfg/apps/payments/migrations/0002_network_providercurrency_and_more.py +0 -241
- django_cfg/apps/payments/migrations/0003_add_usd_rate_cache.py +0 -30
- django_cfg/apps/payments/models/events.py +0 -73
- django_cfg/apps/payments/serializers/__init__.py +0 -57
- django_cfg/apps/payments/serializers/api_keys.py +0 -51
- django_cfg/apps/payments/serializers/balance.py +0 -59
- django_cfg/apps/payments/serializers/currencies.py +0 -63
- django_cfg/apps/payments/serializers/payments.py +0 -62
- django_cfg/apps/payments/serializers/subscriptions.py +0 -71
- django_cfg/apps/payments/serializers/tariffs.py +0 -56
- django_cfg/apps/payments/services/billing/__init__.py +0 -8
- django_cfg/apps/payments/services/cache/base.py +0 -30
- django_cfg/apps/payments/services/core/fallback_service.py +0 -432
- django_cfg/apps/payments/services/internal_types.py +0 -461
- django_cfg/apps/payments/services/middleware/__init__.py +0 -8
- django_cfg/apps/payments/services/monitoring/__init__.py +0 -22
- django_cfg/apps/payments/services/monitoring/api_schemas.py +0 -76
- django_cfg/apps/payments/services/monitoring/provider_health.py +0 -372
- django_cfg/apps/payments/services/providers/cryptapi/__init__.py +0 -4
- django_cfg/apps/payments/services/providers/cryptapi/config.py +0 -8
- django_cfg/apps/payments/services/providers/cryptapi/models.py +0 -192
- django_cfg/apps/payments/services/providers/cryptapi/provider.py +0 -439
- django_cfg/apps/payments/services/providers/cryptomus/__init__.py +0 -4
- django_cfg/apps/payments/services/providers/cryptomus/models.py +0 -176
- django_cfg/apps/payments/services/providers/cryptomus/provider.py +0 -429
- django_cfg/apps/payments/services/providers/cryptomus/provider_v2.py +0 -564
- django_cfg/apps/payments/services/providers/models/__init__.py +0 -34
- django_cfg/apps/payments/services/providers/models/currencies.py +0 -190
- django_cfg/apps/payments/services/providers/nowpayments/__init__.py +0 -4
- django_cfg/apps/payments/services/providers/nowpayments/models.py +0 -196
- django_cfg/apps/payments/services/providers/nowpayments/provider.py +0 -380
- django_cfg/apps/payments/services/providers/stripe/__init__.py +0 -4
- django_cfg/apps/payments/services/providers/stripe/models.py +0 -184
- django_cfg/apps/payments/services/providers/stripe/provider.py +0 -109
- django_cfg/apps/payments/services/security/__init__.py +0 -34
- django_cfg/apps/payments/services/security/error_handler.py +0 -635
- django_cfg/apps/payments/services/security/payment_notifications.py +0 -342
- django_cfg/apps/payments/services/security/webhook_validator.py +0 -474
- django_cfg/apps/payments/static/payments/css/payments.css +0 -340
- django_cfg/apps/payments/static/payments/js/notifications.js +0 -202
- django_cfg/apps/payments/static/payments/js/payment-utils.js +0 -318
- django_cfg/apps/payments/static/payments/js/theme.js +0 -86
- django_cfg/apps/payments/tasks/__init__.py +0 -12
- django_cfg/apps/payments/tasks/webhook_processing.py +0 -177
- django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +0 -50
- django_cfg/apps/payments/templates/payments/base.html +0 -182
- django_cfg/apps/payments/templates/payments/components/payment_card.html +0 -201
- django_cfg/apps/payments/templates/payments/components/payment_qr_code.html +0 -109
- django_cfg/apps/payments/templates/payments/components/progress_bar.html +0 -43
- django_cfg/apps/payments/templates/payments/components/provider_stats.html +0 -40
- django_cfg/apps/payments/templates/payments/components/status_badge.html +0 -34
- django_cfg/apps/payments/templates/payments/components/status_overview.html +0 -148
- django_cfg/apps/payments/templates/payments/dashboard.html +0 -258
- django_cfg/apps/payments/templates/payments/dashboard_simple_test.html +0 -35
- django_cfg/apps/payments/templates/payments/payment_create.html +0 -579
- django_cfg/apps/payments/templates/payments/payment_detail.html +0 -373
- django_cfg/apps/payments/templates/payments/payment_list.html +0 -354
- django_cfg/apps/payments/templates/payments/stats.html +0 -261
- django_cfg/apps/payments/templates/payments/test.html +0 -213
- django_cfg/apps/payments/templatetags/payments_tags.py +0 -315
- django_cfg/apps/payments/utils/__init__.py +0 -43
- django_cfg/apps/payments/utils/billing_utils.py +0 -342
- django_cfg/apps/payments/utils/config_utils.py +0 -239
- django_cfg/apps/payments/utils/middleware_utils.py +0 -228
- django_cfg/apps/payments/utils/validation_utils.py +0 -94
- django_cfg/apps/payments/views/__init__.py +0 -63
- django_cfg/apps/payments/views/api_key_views.py +0 -164
- django_cfg/apps/payments/views/balance_views.py +0 -75
- django_cfg/apps/payments/views/currency_views.py +0 -122
- django_cfg/apps/payments/views/payment_views.py +0 -149
- django_cfg/apps/payments/views/subscription_views.py +0 -135
- django_cfg/apps/payments/views/tariff_views.py +0 -131
- django_cfg/apps/payments/views/templates/__init__.py +0 -25
- django_cfg/apps/payments/views/templates/ajax.py +0 -451
- django_cfg/apps/payments/views/templates/base.py +0 -212
- django_cfg/apps/payments/views/templates/dashboard.py +0 -60
- django_cfg/apps/payments/views/templates/payment_detail.py +0 -102
- django_cfg/apps/payments/views/templates/payment_management.py +0 -158
- django_cfg/apps/payments/views/templates/qr_code.py +0 -174
- django_cfg/apps/payments/views/templates/stats.py +0 -244
- django_cfg/apps/payments/views/templates/utils.py +0 -181
- django_cfg/apps/payments/views/webhook_views.py +0 -266
- django_cfg/apps/payments/viewsets.py +0 -66
- django_cfg/core/integration.py +0 -160
- django_cfg/template_archive/.gitignore +0 -1
- django_cfg/template_archive/__init__.py +0 -0
- django_cfg/urls.py +0 -33
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/WHEEL +0 -0
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,291 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Decorators for API access control and endpoint registration.
|
3
|
-
"""
|
4
|
-
|
5
|
-
import functools
|
6
|
-
from django_cfg.modules.django_logger import get_logger
|
7
|
-
from typing import Optional, List, Callable, Any
|
8
|
-
from django.http import JsonResponse
|
9
|
-
from django.conf import settings
|
10
|
-
from django.utils import timezone
|
11
|
-
from .models import EndpointGroup, Subscription
|
12
|
-
|
13
|
-
logger = get_logger("decorators")
|
14
|
-
|
15
|
-
|
16
|
-
def require_api_key(func: Callable) -> Callable:
|
17
|
-
"""
|
18
|
-
Decorator to require valid API key for function-based views.
|
19
|
-
Works with APIAccessMiddleware.
|
20
|
-
"""
|
21
|
-
@functools.wraps(func)
|
22
|
-
def wrapper(request, *args, **kwargs):
|
23
|
-
if not hasattr(request, 'payment_api_key'):
|
24
|
-
return JsonResponse({
|
25
|
-
'error': {
|
26
|
-
'code': 'MISSING_API_KEY',
|
27
|
-
'message': 'Valid API key required',
|
28
|
-
'timestamp': timezone.now().isoformat(),
|
29
|
-
}
|
30
|
-
}, status=401)
|
31
|
-
|
32
|
-
return func(request, *args, **kwargs)
|
33
|
-
|
34
|
-
return wrapper
|
35
|
-
|
36
|
-
|
37
|
-
def require_subscription(endpoint_group_name: str):
|
38
|
-
"""
|
39
|
-
Decorator to require active subscription for specific endpoint group.
|
40
|
-
|
41
|
-
Args:
|
42
|
-
endpoint_group_name: Name of the endpoint group to check
|
43
|
-
"""
|
44
|
-
def decorator(func: Callable) -> Callable:
|
45
|
-
@functools.wraps(func)
|
46
|
-
def wrapper(request, *args, **kwargs):
|
47
|
-
# Check if middleware already validated subscription
|
48
|
-
if hasattr(request, 'payment_subscription'):
|
49
|
-
subscription = request.payment_subscription
|
50
|
-
if subscription.endpoint_group.name == endpoint_group_name:
|
51
|
-
return func(request, *args, **kwargs)
|
52
|
-
|
53
|
-
# If not validated by middleware, check manually
|
54
|
-
if not hasattr(request, 'payment_api_key'):
|
55
|
-
return JsonResponse({
|
56
|
-
'error': {
|
57
|
-
'code': 'MISSING_API_KEY',
|
58
|
-
'message': 'Valid API key required',
|
59
|
-
'timestamp': timezone.now().isoformat(),
|
60
|
-
}
|
61
|
-
}, status=401)
|
62
|
-
|
63
|
-
try:
|
64
|
-
endpoint_group = EndpointGroup.objects.get(
|
65
|
-
name=endpoint_group_name,
|
66
|
-
is_active=True
|
67
|
-
)
|
68
|
-
|
69
|
-
subscription = Subscription.objects.filter(
|
70
|
-
user=request.payment_api_key.user,
|
71
|
-
endpoint_group=endpoint_group,
|
72
|
-
status='active',
|
73
|
-
expires_at__gt=timezone.now()
|
74
|
-
).first()
|
75
|
-
|
76
|
-
if not subscription:
|
77
|
-
return JsonResponse({
|
78
|
-
'error': {
|
79
|
-
'code': 'NO_SUBSCRIPTION',
|
80
|
-
'message': f'Active subscription required for {endpoint_group.display_name}',
|
81
|
-
'timestamp': timezone.now().isoformat(),
|
82
|
-
}
|
83
|
-
}, status=403)
|
84
|
-
|
85
|
-
# Store subscription in request
|
86
|
-
request.payment_subscription = subscription
|
87
|
-
|
88
|
-
return func(request, *args, **kwargs)
|
89
|
-
|
90
|
-
except EndpointGroup.DoesNotExist:
|
91
|
-
logger.error(f"Endpoint group '{endpoint_group_name}' not found")
|
92
|
-
return JsonResponse({
|
93
|
-
'error': {
|
94
|
-
'code': 'INVALID_ENDPOINT_GROUP',
|
95
|
-
'message': 'Invalid endpoint group',
|
96
|
-
'timestamp': timezone.now().isoformat(),
|
97
|
-
}
|
98
|
-
}, status=500)
|
99
|
-
|
100
|
-
return wrapper
|
101
|
-
return decorator
|
102
|
-
|
103
|
-
|
104
|
-
def require_tier(minimum_tier: str):
|
105
|
-
"""
|
106
|
-
Decorator to require minimum subscription tier.
|
107
|
-
|
108
|
-
Args:
|
109
|
-
minimum_tier: Minimum required tier (basic, premium, enterprise)
|
110
|
-
"""
|
111
|
-
tier_hierarchy = {
|
112
|
-
'basic': 1,
|
113
|
-
'premium': 2,
|
114
|
-
'enterprise': 3,
|
115
|
-
}
|
116
|
-
|
117
|
-
def decorator(func: Callable) -> Callable:
|
118
|
-
@functools.wraps(func)
|
119
|
-
def wrapper(request, *args, **kwargs):
|
120
|
-
if not hasattr(request, 'payment_subscription'):
|
121
|
-
return JsonResponse({
|
122
|
-
'error': {
|
123
|
-
'code': 'NO_SUBSCRIPTION',
|
124
|
-
'message': 'Active subscription required',
|
125
|
-
'timestamp': timezone.now().isoformat(),
|
126
|
-
}
|
127
|
-
}, status=403)
|
128
|
-
|
129
|
-
subscription = request.payment_subscription
|
130
|
-
current_tier_level = tier_hierarchy.get(subscription.tier, 0)
|
131
|
-
required_tier_level = tier_hierarchy.get(minimum_tier, 999)
|
132
|
-
|
133
|
-
if current_tier_level < required_tier_level:
|
134
|
-
return JsonResponse({
|
135
|
-
'error': {
|
136
|
-
'code': 'INSUFFICIENT_TIER',
|
137
|
-
'message': f'Tier {minimum_tier} or higher required',
|
138
|
-
'current_tier': subscription.tier,
|
139
|
-
'required_tier': minimum_tier,
|
140
|
-
'timestamp': timezone.now().isoformat(),
|
141
|
-
}
|
142
|
-
}, status=403)
|
143
|
-
|
144
|
-
return func(request, *args, **kwargs)
|
145
|
-
|
146
|
-
return wrapper
|
147
|
-
return decorator
|
148
|
-
|
149
|
-
|
150
|
-
def track_usage(cost_per_request: float = 0.0):
|
151
|
-
"""
|
152
|
-
Decorator to track API usage and deduct costs.
|
153
|
-
|
154
|
-
Args:
|
155
|
-
cost_per_request: Cost to deduct per successful request
|
156
|
-
"""
|
157
|
-
def decorator(func: Callable) -> Callable:
|
158
|
-
@functools.wraps(func)
|
159
|
-
def wrapper(request, *args, **kwargs):
|
160
|
-
# Execute the function
|
161
|
-
response = func(request, *args, **kwargs)
|
162
|
-
|
163
|
-
# Track usage if successful and we have subscription
|
164
|
-
if (hasattr(request, 'payment_subscription') and
|
165
|
-
hasattr(response, 'status_code') and
|
166
|
-
200 <= response.status_code < 300 and
|
167
|
-
cost_per_request > 0):
|
168
|
-
|
169
|
-
try:
|
170
|
-
from .models import Transaction
|
171
|
-
|
172
|
-
subscription = request.payment_subscription
|
173
|
-
|
174
|
-
# Create billing transaction
|
175
|
-
Transaction.objects.create(
|
176
|
-
user=subscription.user,
|
177
|
-
subscription=subscription,
|
178
|
-
transaction_type='debit',
|
179
|
-
amount_usd=-cost_per_request,
|
180
|
-
description=f"API usage: {request.method} {request.path}",
|
181
|
-
metadata={
|
182
|
-
'endpoint': request.path,
|
183
|
-
'method': request.method,
|
184
|
-
'cost_per_request': cost_per_request,
|
185
|
-
}
|
186
|
-
)
|
187
|
-
|
188
|
-
except Exception as e:
|
189
|
-
logger.error(f"Error tracking usage: {e}")
|
190
|
-
|
191
|
-
return response
|
192
|
-
|
193
|
-
return wrapper
|
194
|
-
return decorator
|
195
|
-
|
196
|
-
|
197
|
-
def register_endpoint(endpoint_group_name: str,
|
198
|
-
display_name: Optional[str] = None,
|
199
|
-
description: Optional[str] = None,
|
200
|
-
require_api_key: bool = True):
|
201
|
-
"""
|
202
|
-
Decorator to automatically register endpoint with the system.
|
203
|
-
This creates or updates EndpointGroup records.
|
204
|
-
|
205
|
-
Args:
|
206
|
-
endpoint_group_name: Internal name for the endpoint group
|
207
|
-
display_name: Human-readable name
|
208
|
-
description: Description of the endpoint functionality
|
209
|
-
require_api_key: Whether this endpoint requires API key
|
210
|
-
"""
|
211
|
-
def decorator(func: Callable) -> Callable:
|
212
|
-
@functools.wraps(func)
|
213
|
-
def wrapper(*args, **kwargs):
|
214
|
-
# Auto-register endpoint group if it doesn't exist
|
215
|
-
try:
|
216
|
-
endpoint_group, created = EndpointGroup.objects.get_or_create(
|
217
|
-
name=endpoint_group_name,
|
218
|
-
defaults={
|
219
|
-
'display_name': display_name or endpoint_group_name.replace('_', ' ').title(),
|
220
|
-
'description': description or f'Auto-registered endpoint group: {endpoint_group_name}',
|
221
|
-
'require_api_key': require_api_key,
|
222
|
-
'is_active': True,
|
223
|
-
}
|
224
|
-
)
|
225
|
-
|
226
|
-
if created:
|
227
|
-
logger.info(f"Auto-registered endpoint group: {endpoint_group_name}")
|
228
|
-
|
229
|
-
except Exception as e:
|
230
|
-
logger.error(f"Error auto-registering endpoint group: {e}")
|
231
|
-
|
232
|
-
return func(*args, **kwargs)
|
233
|
-
|
234
|
-
return wrapper
|
235
|
-
return decorator
|
236
|
-
|
237
|
-
|
238
|
-
def check_usage_limit(func: Callable) -> Callable:
|
239
|
-
"""
|
240
|
-
Decorator to check subscription usage limits before processing request.
|
241
|
-
"""
|
242
|
-
@functools.wraps(func)
|
243
|
-
def wrapper(request, *args, **kwargs):
|
244
|
-
if hasattr(request, 'payment_subscription'):
|
245
|
-
subscription = request.payment_subscription
|
246
|
-
|
247
|
-
# Check if usage limit exceeded
|
248
|
-
if (subscription.usage_limit > 0 and
|
249
|
-
subscription.usage_current >= subscription.usage_limit):
|
250
|
-
|
251
|
-
return JsonResponse({
|
252
|
-
'error': {
|
253
|
-
'code': 'USAGE_EXCEEDED',
|
254
|
-
'message': 'Monthly usage limit exceeded',
|
255
|
-
'current_usage': subscription.usage_current,
|
256
|
-
'usage_limit': subscription.usage_limit,
|
257
|
-
'reset_date': subscription.next_billing.isoformat() if subscription.next_billing else None,
|
258
|
-
'timestamp': timezone.now().isoformat(),
|
259
|
-
}
|
260
|
-
}, status=429)
|
261
|
-
|
262
|
-
return func(request, *args, **kwargs)
|
263
|
-
|
264
|
-
return wrapper
|
265
|
-
|
266
|
-
|
267
|
-
# Utility decorator combinations
|
268
|
-
def api_endpoint(endpoint_group_name: str,
|
269
|
-
minimum_tier: str = 'basic',
|
270
|
-
cost_per_request: float = 0.0):
|
271
|
-
"""
|
272
|
-
Combination decorator for typical API endpoint protection.
|
273
|
-
|
274
|
-
Args:
|
275
|
-
endpoint_group_name: Name of the endpoint group
|
276
|
-
minimum_tier: Minimum subscription tier required
|
277
|
-
cost_per_request: Cost to charge per successful request
|
278
|
-
"""
|
279
|
-
def decorator(func: Callable) -> Callable:
|
280
|
-
# Apply decorators in reverse order (they wrap from inside out)
|
281
|
-
decorated_func = func
|
282
|
-
decorated_func = track_usage(cost_per_request)(decorated_func)
|
283
|
-
decorated_func = check_usage_limit(decorated_func)
|
284
|
-
decorated_func = require_tier(minimum_tier)(decorated_func)
|
285
|
-
decorated_func = require_subscription(endpoint_group_name)(decorated_func)
|
286
|
-
decorated_func = require_api_key(decorated_func)
|
287
|
-
decorated_func = register_endpoint(endpoint_group_name)(decorated_func)
|
288
|
-
|
289
|
-
return decorated_func
|
290
|
-
|
291
|
-
return decorator
|
@@ -1,146 +0,0 @@
|
|
1
|
-
# Payment Management Commands
|
2
|
-
|
3
|
-
Optimized management commands for Django CFG payments system.
|
4
|
-
|
5
|
-
## Available Commands
|
6
|
-
|
7
|
-
### 1. `manage_currencies` - Currency and Rate Management
|
8
|
-
|
9
|
-
Universal command for all currency-related operations.
|
10
|
-
|
11
|
-
#### Usage Examples:
|
12
|
-
|
13
|
-
```bash
|
14
|
-
# Update USD exchange rates only
|
15
|
-
python manage.py manage_currencies --rates-only
|
16
|
-
|
17
|
-
# Update specific currency rate
|
18
|
-
python manage.py manage_currencies --rates-only --currency ETH
|
19
|
-
|
20
|
-
# Initial population (empty database)
|
21
|
-
python manage.py manage_currencies --populate
|
22
|
-
|
23
|
-
# Full update with fresh rates
|
24
|
-
python manage.py manage_currencies --force
|
25
|
-
|
26
|
-
# Dry run to see what would be updated
|
27
|
-
python manage.py manage_currencies --dry-run
|
28
|
-
|
29
|
-
# Limit number of currencies processed
|
30
|
-
python manage.py manage_currencies --populate --max-crypto 100 --max-fiat 20
|
31
|
-
```
|
32
|
-
|
33
|
-
#### Options:
|
34
|
-
- `--populate` - Initial population mode for empty database
|
35
|
-
- `--rates-only` - Only update USD exchange rates
|
36
|
-
- `--currency CODE` - Update specific currency (e.g., BTC, ETH)
|
37
|
-
- `--force` - Force refresh all data even if fresh
|
38
|
-
- `--dry-run` - Show what would be done without changes
|
39
|
-
- `--max-crypto N` - Limit crypto currencies (default: 200)
|
40
|
-
- `--max-fiat N` - Limit fiat currencies (default: 50)
|
41
|
-
|
42
|
-
---
|
43
|
-
|
44
|
-
### 2. `manage_providers` - Payment Provider Management
|
45
|
-
|
46
|
-
Universal command for all provider-related operations.
|
47
|
-
|
48
|
-
#### Usage Examples:
|
49
|
-
|
50
|
-
```bash
|
51
|
-
# Sync all active providers
|
52
|
-
python manage.py manage_providers
|
53
|
-
|
54
|
-
# Sync specific provider
|
55
|
-
python manage.py manage_providers --provider nowpayments
|
56
|
-
|
57
|
-
# Sync multiple providers
|
58
|
-
python manage.py manage_providers --provider nowpayments,cryptomus
|
59
|
-
|
60
|
-
# Sync providers + update USD rates
|
61
|
-
python manage.py manage_providers --with-rates
|
62
|
-
|
63
|
-
# Show provider statistics
|
64
|
-
python manage.py manage_providers --stats
|
65
|
-
|
66
|
-
# Dry run to see what would be synced
|
67
|
-
python manage.py manage_providers --dry-run --verbose
|
68
|
-
```
|
69
|
-
|
70
|
-
#### Options:
|
71
|
-
- `--provider NAME` - Specific provider(s) to sync (comma-separated)
|
72
|
-
- `--all` - Sync all available providers
|
73
|
-
- `--with-rates` - Also update USD exchange rates after sync
|
74
|
-
- `--stats` - Show provider statistics
|
75
|
-
- `--dry-run` - Show what would be synced without changes
|
76
|
-
- `--verbose` - Show detailed progress information
|
77
|
-
|
78
|
-
---
|
79
|
-
|
80
|
-
### 3. `currency_stats` - Statistics and Reports
|
81
|
-
|
82
|
-
Display currency database statistics and health information.
|
83
|
-
|
84
|
-
#### Usage Examples:
|
85
|
-
|
86
|
-
```bash
|
87
|
-
# Basic statistics
|
88
|
-
python manage.py currency_stats
|
89
|
-
|
90
|
-
# Detailed breakdown
|
91
|
-
python manage.py currency_stats --detailed
|
92
|
-
|
93
|
-
# Top currencies by value
|
94
|
-
python manage.py currency_stats --top 10
|
95
|
-
|
96
|
-
# Check rate freshness
|
97
|
-
python manage.py currency_stats --check-rates
|
98
|
-
```
|
99
|
-
|
100
|
-
---
|
101
|
-
|
102
|
-
## Migration from Old Commands
|
103
|
-
|
104
|
-
| Old Command | New Command |
|
105
|
-
|-------------|-------------|
|
106
|
-
| `populate_currencies` | `manage_currencies --populate` |
|
107
|
-
| `update_currencies` | `manage_currencies` |
|
108
|
-
| `update_currency_rates` | `manage_currencies --rates-only` |
|
109
|
-
| `sync_providers` | `manage_providers` |
|
110
|
-
| `currency_stats` | `currency_stats` (unchanged) |
|
111
|
-
|
112
|
-
## Automation Examples
|
113
|
-
|
114
|
-
### Daily Rate Updates (Crontab)
|
115
|
-
```bash
|
116
|
-
# Update rates every 6 hours
|
117
|
-
0 */6 * * * cd /path/to/project && python manage.py manage_currencies --rates-only
|
118
|
-
|
119
|
-
# Sync providers once daily
|
120
|
-
0 2 * * * cd /path/to/project && python manage.py manage_providers --with-rates
|
121
|
-
```
|
122
|
-
|
123
|
-
### Initial Setup
|
124
|
-
```bash
|
125
|
-
# 1. Populate base currencies
|
126
|
-
python manage.py manage_currencies --populate
|
127
|
-
|
128
|
-
# 2. Sync payment providers
|
129
|
-
python manage.py manage_providers
|
130
|
-
|
131
|
-
# 3. Check statistics
|
132
|
-
python manage.py manage_providers --stats
|
133
|
-
python manage.py currency_stats
|
134
|
-
```
|
135
|
-
|
136
|
-
---
|
137
|
-
|
138
|
-
## Features
|
139
|
-
|
140
|
-
- **🚀 Fast**: Optimized database queries and caching
|
141
|
-
- **📊 Progress**: Real-time progress reporting and statistics
|
142
|
-
- **🔄 Atomic**: Transaction safety with rollback on errors
|
143
|
-
- **🎯 Flexible**: Multiple operation modes and options
|
144
|
-
- **📈 Pydantic**: Full type safety with Pydantic models
|
145
|
-
- **🛡️ Safe**: Dry-run mode for testing changes
|
146
|
-
- **📝 Verbose**: Detailed logging and error reporting
|