django-cfg 1.3.1__py3-none-any.whl → 1.3.5__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/payments/admin_interface/old/payments/base.html +175 -0
- django_cfg/apps/payments/admin_interface/old/payments/components/dev_tool_card.html +125 -0
- django_cfg/apps/payments/admin_interface/old/payments/components/ngrok_status_card.html +113 -0
- django_cfg/apps/payments/admin_interface/old/payments/components/status_card.html +35 -0
- django_cfg/apps/payments/admin_interface/old/payments/payment_dashboard.html +309 -0
- django_cfg/apps/payments/admin_interface/old/payments/payment_form.html +303 -0
- django_cfg/apps/payments/admin_interface/old/payments/payment_list.html +382 -0
- django_cfg/apps/payments/admin_interface/old/payments/webhook_dashboard.html +518 -0
- django_cfg/apps/payments/{static → admin_interface/old/static}/payments/css/components.css +248 -9
- django_cfg/apps/payments/admin_interface/old/static/payments/js/ngrok-status.js +163 -0
- django_cfg/apps/payments/admin_interface/serializers/__init__.py +39 -0
- django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +149 -0
- django_cfg/apps/payments/admin_interface/serializers/webhook_serializers.py +114 -0
- django_cfg/apps/payments/admin_interface/templates/payments/base.html +55 -90
- django_cfg/apps/payments/admin_interface/templates/payments/components/dialog.html +81 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/ngrok_help_dialog.html +112 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/ngrok_status.html +175 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_card.html +21 -17
- django_cfg/apps/payments/admin_interface/templates/payments/payment_dashboard.html +123 -250
- django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +170 -269
- django_cfg/apps/payments/admin_interface/templates/payments/payment_list.html +152 -355
- django_cfg/apps/payments/admin_interface/templates/payments/webhook_dashboard.html +202 -551
- django_cfg/apps/payments/admin_interface/views/__init__.py +25 -14
- django_cfg/apps/payments/admin_interface/views/api/__init__.py +20 -0
- django_cfg/apps/payments/admin_interface/views/api/payments.py +191 -0
- django_cfg/apps/payments/admin_interface/views/api/stats.py +206 -0
- django_cfg/apps/payments/admin_interface/views/api/users.py +60 -0
- django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +257 -0
- django_cfg/apps/payments/admin_interface/views/api/webhook_public.py +70 -0
- django_cfg/apps/payments/admin_interface/views/base.py +114 -0
- django_cfg/apps/payments/admin_interface/views/dashboard.py +60 -0
- django_cfg/apps/payments/admin_interface/views/forms.py +94 -0
- django_cfg/apps/payments/config/helpers.py +2 -2
- django_cfg/apps/payments/management/commands/cleanup_expired_data.py +429 -0
- django_cfg/apps/payments/management/commands/currency_stats.py +443 -0
- django_cfg/apps/payments/management/commands/manage_currencies.py +9 -20
- django_cfg/apps/payments/management/commands/manage_providers.py +5 -5
- django_cfg/apps/payments/management/commands/process_pending_payments.py +357 -0
- django_cfg/apps/payments/management/commands/test_providers.py +434 -0
- django_cfg/apps/payments/middleware/api_access.py +35 -34
- django_cfg/apps/payments/migrations/0001_initial.py +1 -1
- django_cfg/apps/payments/models/balance.py +5 -2
- django_cfg/apps/payments/models/managers/api_key_managers.py +6 -2
- django_cfg/apps/payments/models/managers/balance_managers.py +3 -3
- django_cfg/apps/payments/models/managers/payment_managers.py +5 -0
- django_cfg/apps/payments/models/managers/subscription_managers.py +3 -3
- django_cfg/apps/payments/models/subscriptions.py +0 -24
- django_cfg/apps/payments/services/cache/__init__.py +1 -1
- django_cfg/apps/payments/services/cache_service/__init__.py +143 -0
- django_cfg/apps/payments/services/cache_service/api_key_cache.py +37 -0
- django_cfg/apps/payments/services/cache_service/interfaces.py +32 -0
- django_cfg/apps/payments/services/cache_service/keys.py +49 -0
- django_cfg/apps/payments/services/cache_service/rate_limit_cache.py +47 -0
- django_cfg/apps/payments/services/cache_service/simple_cache.py +101 -0
- django_cfg/apps/payments/services/core/balance_service.py +13 -2
- django_cfg/apps/payments/services/core/payment_service.py +49 -22
- django_cfg/apps/payments/services/integrations/ngrok_service.py +3 -3
- django_cfg/apps/payments/services/providers/registry.py +20 -0
- django_cfg/apps/payments/signals/api_key_signals.py +2 -2
- django_cfg/apps/payments/signals/balance_signals.py +8 -5
- django_cfg/apps/payments/static/payments/js/api-client.js +385 -0
- django_cfg/apps/payments/static/payments/js/ngrok-status.js +58 -0
- django_cfg/apps/payments/static/payments/js/payment-dashboard.js +50 -0
- django_cfg/apps/payments/static/payments/js/payment-form.js +175 -0
- django_cfg/apps/payments/static/payments/js/payment-list.js +95 -0
- django_cfg/apps/payments/static/payments/js/webhook-dashboard.js +154 -0
- django_cfg/apps/payments/urls.py +4 -0
- django_cfg/apps/payments/urls_admin.py +37 -18
- django_cfg/apps/payments/views/api/api_keys.py +14 -0
- django_cfg/apps/payments/views/api/base.py +1 -0
- django_cfg/apps/payments/views/api/currencies.py +2 -2
- django_cfg/apps/payments/views/api/payments.py +11 -5
- django_cfg/apps/payments/views/api/subscriptions.py +36 -31
- django_cfg/apps/payments/views/overview/__init__.py +40 -0
- django_cfg/apps/payments/views/overview/serializers.py +205 -0
- django_cfg/apps/payments/views/overview/services.py +439 -0
- django_cfg/apps/payments/views/overview/urls.py +27 -0
- django_cfg/apps/payments/views/overview/views.py +231 -0
- django_cfg/apps/payments/views/serializers/api_keys.py +20 -6
- django_cfg/apps/payments/views/serializers/balances.py +5 -8
- django_cfg/apps/payments/views/serializers/currencies.py +2 -6
- django_cfg/apps/payments/views/serializers/payments.py +37 -32
- django_cfg/apps/payments/views/serializers/subscriptions.py +4 -26
- django_cfg/apps/urls.py +2 -1
- django_cfg/core/config.py +25 -15
- django_cfg/core/generation.py +12 -12
- django_cfg/core/integration/display/startup.py +1 -1
- django_cfg/core/validation.py +4 -4
- django_cfg/management/commands/show_config.py +2 -2
- django_cfg/management/commands/tree.py +1 -3
- django_cfg/middleware/__init__.py +2 -0
- django_cfg/middleware/static_nocache.py +55 -0
- django_cfg/models/payments.py +13 -15
- django_cfg/models/security.py +15 -0
- django_cfg/modules/django_ngrok.py +6 -0
- django_cfg/modules/django_unfold/dashboard.py +1 -3
- django_cfg/utils/smart_defaults.py +51 -5
- {django_cfg-1.3.1.dist-info → django_cfg-1.3.5.dist-info}/METADATA +1 -1
- {django_cfg-1.3.1.dist-info → django_cfg-1.3.5.dist-info}/RECORD +111 -69
- django_cfg/apps/payments/admin_interface/templates/payments/components/dev_tool_card.html +0 -38
- django_cfg/apps/payments/admin_interface/views/payment_views.py +0 -259
- django_cfg/apps/payments/admin_interface/views/webhook_dashboard.py +0 -37
- django_cfg/apps/payments/services/cache/cache_service.py +0 -235
- /django_cfg/apps/payments/admin_interface/{templates → old}/payments/components/loading_spinner.html +0 -0
- /django_cfg/apps/payments/admin_interface/{templates → old}/payments/components/notification.html +0 -0
- /django_cfg/apps/payments/admin_interface/{templates → old}/payments/components/provider_card.html +0 -0
- /django_cfg/apps/payments/admin_interface/{templates → old}/payments/currency_converter.html +0 -0
- /django_cfg/apps/payments/admin_interface/{templates → old}/payments/payment_status.html +0 -0
- /django_cfg/apps/payments/{static → admin_interface/old/static}/payments/css/dashboard.css +0 -0
- /django_cfg/apps/payments/{static → admin_interface/old/static}/payments/js/components.js +0 -0
- /django_cfg/apps/payments/{static → admin_interface/old/static}/payments/js/utils.js +0 -0
- {django_cfg-1.3.1.dist-info → django_cfg-1.3.5.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.1.dist-info → django_cfg-1.3.5.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.3.1.dist-info → django_cfg-1.3.5.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,429 @@
|
|
1
|
+
"""
|
2
|
+
Cleanup Expired Data Management Command for Universal Payment System v2.0.
|
3
|
+
|
4
|
+
Clean up expired payments, sessions, and other temporary data.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from datetime import timedelta
|
8
|
+
from typing import List, Dict, Any, Optional
|
9
|
+
|
10
|
+
from django.core.management.base import BaseCommand, CommandError
|
11
|
+
from django.utils import timezone
|
12
|
+
from django.db import transaction
|
13
|
+
from django.db.models import Q, Count
|
14
|
+
from django.core.cache import cache
|
15
|
+
|
16
|
+
from django_cfg.modules.django_logger import get_logger
|
17
|
+
from django_cfg.apps.payments.models import UniversalPayment, APIKey, Transaction
|
18
|
+
from django_cfg.apps.payments.services.cache_service import get_cache_service
|
19
|
+
|
20
|
+
logger = get_logger("cleanup_expired_data")
|
21
|
+
|
22
|
+
|
23
|
+
class Command(BaseCommand):
|
24
|
+
"""
|
25
|
+
Clean up expired data from the payment system.
|
26
|
+
|
27
|
+
Features:
|
28
|
+
- Remove expired payments
|
29
|
+
- Clean up expired API keys
|
30
|
+
- Remove old transaction logs
|
31
|
+
- Clear stale cache entries
|
32
|
+
- Comprehensive logging and statistics
|
33
|
+
"""
|
34
|
+
|
35
|
+
help = 'Clean up expired data from the payment system'
|
36
|
+
|
37
|
+
def add_arguments(self, parser):
|
38
|
+
"""Add command line arguments."""
|
39
|
+
parser.add_argument(
|
40
|
+
'--payments-age-days',
|
41
|
+
type=int,
|
42
|
+
default=30,
|
43
|
+
help='Remove failed/expired payments older than N days (default: 30)'
|
44
|
+
)
|
45
|
+
|
46
|
+
parser.add_argument(
|
47
|
+
'--transactions-age-days',
|
48
|
+
type=int,
|
49
|
+
default=90,
|
50
|
+
help='Remove old transaction logs older than N days (default: 90)'
|
51
|
+
)
|
52
|
+
|
53
|
+
parser.add_argument(
|
54
|
+
'--api-keys',
|
55
|
+
action='store_true',
|
56
|
+
help='Clean up expired API keys'
|
57
|
+
)
|
58
|
+
|
59
|
+
parser.add_argument(
|
60
|
+
'--cache',
|
61
|
+
action='store_true',
|
62
|
+
help='Clear stale cache entries'
|
63
|
+
)
|
64
|
+
|
65
|
+
parser.add_argument(
|
66
|
+
'--all',
|
67
|
+
action='store_true',
|
68
|
+
help='Clean up all types of expired data'
|
69
|
+
)
|
70
|
+
|
71
|
+
parser.add_argument(
|
72
|
+
'--payments-only',
|
73
|
+
action='store_true',
|
74
|
+
help='Clean up only expired payments'
|
75
|
+
)
|
76
|
+
|
77
|
+
parser.add_argument(
|
78
|
+
'--dry-run',
|
79
|
+
action='store_true',
|
80
|
+
help='Show what would be cleaned without making changes'
|
81
|
+
)
|
82
|
+
|
83
|
+
parser.add_argument(
|
84
|
+
'--batch-size',
|
85
|
+
type=int,
|
86
|
+
default=1000,
|
87
|
+
help='Number of records to process in each batch (default: 1000)'
|
88
|
+
)
|
89
|
+
|
90
|
+
parser.add_argument(
|
91
|
+
'--verbose',
|
92
|
+
action='store_true',
|
93
|
+
help='Show detailed cleanup information'
|
94
|
+
)
|
95
|
+
|
96
|
+
def handle(self, *args, **options):
|
97
|
+
"""Execute the command."""
|
98
|
+
try:
|
99
|
+
self.options = options
|
100
|
+
self.dry_run = options['dry_run']
|
101
|
+
self.verbose = options['verbose']
|
102
|
+
|
103
|
+
self.show_header()
|
104
|
+
|
105
|
+
# Initialize statistics
|
106
|
+
self.stats = {
|
107
|
+
'payments_removed': 0,
|
108
|
+
'transactions_removed': 0,
|
109
|
+
'api_keys_removed': 0,
|
110
|
+
'cache_entries_cleared': 0,
|
111
|
+
'errors': 0
|
112
|
+
}
|
113
|
+
|
114
|
+
# Determine what to clean
|
115
|
+
clean_all = options['all']
|
116
|
+
payments_only = options['payments_only']
|
117
|
+
|
118
|
+
if payments_only:
|
119
|
+
# Only clean payments
|
120
|
+
self.cleanup_expired_payments()
|
121
|
+
elif clean_all or not any([options['api_keys'], options['cache']]):
|
122
|
+
# Default: clean payments and transactions
|
123
|
+
self.cleanup_expired_payments()
|
124
|
+
self.cleanup_old_transactions()
|
125
|
+
|
126
|
+
if not payments_only and (clean_all or options['api_keys']):
|
127
|
+
self.cleanup_expired_api_keys()
|
128
|
+
|
129
|
+
if not payments_only and (clean_all or options['cache']):
|
130
|
+
self.cleanup_stale_cache()
|
131
|
+
|
132
|
+
self.show_summary()
|
133
|
+
|
134
|
+
except Exception as e:
|
135
|
+
logger.error(f"Cleanup expired data command failed: {e}")
|
136
|
+
raise CommandError(f"Failed to cleanup expired data: {e}")
|
137
|
+
|
138
|
+
def show_header(self):
|
139
|
+
"""Display command header."""
|
140
|
+
mode = "DRY RUN" if self.dry_run else "LIVE MODE"
|
141
|
+
self.stdout.write(
|
142
|
+
self.style.SUCCESS("=" * 60)
|
143
|
+
)
|
144
|
+
self.stdout.write(
|
145
|
+
self.style.SUCCESS(f"🧹 CLEANUP EXPIRED DATA - {mode}")
|
146
|
+
)
|
147
|
+
self.stdout.write(
|
148
|
+
self.style.SUCCESS("=" * 60)
|
149
|
+
)
|
150
|
+
self.stdout.write(f"Started: {timezone.now().strftime('%Y-%m-%d %H:%M:%S UTC')}")
|
151
|
+
self.stdout.write("")
|
152
|
+
|
153
|
+
def cleanup_expired_payments(self):
|
154
|
+
"""Clean up expired and failed payments."""
|
155
|
+
self.stdout.write(self.style.SUCCESS("🗑️ CLEANING UP EXPIRED PAYMENTS"))
|
156
|
+
self.stdout.write("-" * 40)
|
157
|
+
|
158
|
+
# Calculate cutoff date
|
159
|
+
cutoff_date = timezone.now() - timedelta(days=self.options['payments_age_days'])
|
160
|
+
|
161
|
+
# Find payments to remove
|
162
|
+
expired_payments = UniversalPayment.objects.filter(
|
163
|
+
Q(status__in=['failed', 'expired', 'cancelled']) &
|
164
|
+
Q(created_at__lt=cutoff_date)
|
165
|
+
)
|
166
|
+
|
167
|
+
total_count = expired_payments.count()
|
168
|
+
self.stdout.write(f"Found {total_count} expired payments to remove")
|
169
|
+
|
170
|
+
if total_count == 0:
|
171
|
+
self.stdout.write(self.style.WARNING("No expired payments to clean up"))
|
172
|
+
return
|
173
|
+
|
174
|
+
if self.dry_run:
|
175
|
+
self.stdout.write(f"[DRY RUN] Would remove {total_count} expired payments")
|
176
|
+
self.stats['payments_removed'] = total_count
|
177
|
+
return
|
178
|
+
|
179
|
+
# Remove in batches
|
180
|
+
batch_size = self.options['batch_size']
|
181
|
+
removed_count = 0
|
182
|
+
|
183
|
+
try:
|
184
|
+
while True:
|
185
|
+
# Get batch of payments to delete
|
186
|
+
batch_ids = list(
|
187
|
+
expired_payments.values_list('id', flat=True)[:batch_size]
|
188
|
+
)
|
189
|
+
|
190
|
+
if not batch_ids:
|
191
|
+
break
|
192
|
+
|
193
|
+
with transaction.atomic():
|
194
|
+
# Delete the batch
|
195
|
+
deleted_count = UniversalPayment.objects.filter(
|
196
|
+
id__in=batch_ids
|
197
|
+
).delete()[0]
|
198
|
+
|
199
|
+
removed_count += deleted_count
|
200
|
+
|
201
|
+
if self.verbose:
|
202
|
+
self.stdout.write(f" Removed batch: {deleted_count} payments")
|
203
|
+
|
204
|
+
# Update progress
|
205
|
+
progress = (removed_count / total_count) * 100
|
206
|
+
self.stdout.write(f"Progress: {removed_count}/{total_count} ({progress:.1f}%)")
|
207
|
+
|
208
|
+
self.stats['payments_removed'] = removed_count
|
209
|
+
logger.info(f"Removed {removed_count} expired payments")
|
210
|
+
|
211
|
+
except Exception as e:
|
212
|
+
logger.error(f"Error cleaning up payments: {e}")
|
213
|
+
self.stats['errors'] += 1
|
214
|
+
self.stdout.write(self.style.ERROR(f"Error: {e}"))
|
215
|
+
|
216
|
+
self.stdout.write("")
|
217
|
+
|
218
|
+
def cleanup_old_transactions(self):
|
219
|
+
"""Clean up old transaction logs."""
|
220
|
+
self.stdout.write(self.style.SUCCESS("📋 CLEANING UP OLD TRANSACTIONS"))
|
221
|
+
self.stdout.write("-" * 40)
|
222
|
+
|
223
|
+
# Calculate cutoff date
|
224
|
+
cutoff_date = timezone.now() - timedelta(days=self.options['transactions_age_days'])
|
225
|
+
|
226
|
+
# Find transactions to remove (keep important ones)
|
227
|
+
old_transactions = Transaction.objects.filter(
|
228
|
+
created_at__lt=cutoff_date
|
229
|
+
).exclude(
|
230
|
+
# Keep transactions with payment references (important transactions)
|
231
|
+
payment_id__isnull=False
|
232
|
+
)
|
233
|
+
|
234
|
+
total_count = old_transactions.count()
|
235
|
+
self.stdout.write(f"Found {total_count} old transactions to remove")
|
236
|
+
|
237
|
+
if total_count == 0:
|
238
|
+
self.stdout.write(self.style.WARNING("No old transactions to clean up"))
|
239
|
+
return
|
240
|
+
|
241
|
+
if self.dry_run:
|
242
|
+
self.stdout.write(f"[DRY RUN] Would remove {total_count} old transactions")
|
243
|
+
self.stats['transactions_removed'] = total_count
|
244
|
+
return
|
245
|
+
|
246
|
+
# Remove in batches
|
247
|
+
batch_size = self.options['batch_size']
|
248
|
+
removed_count = 0
|
249
|
+
|
250
|
+
try:
|
251
|
+
while True:
|
252
|
+
# Get batch of transactions to delete
|
253
|
+
batch_ids = list(
|
254
|
+
old_transactions.values_list('id', flat=True)[:batch_size]
|
255
|
+
)
|
256
|
+
|
257
|
+
if not batch_ids:
|
258
|
+
break
|
259
|
+
|
260
|
+
with transaction.atomic():
|
261
|
+
# Delete the batch
|
262
|
+
deleted_count = Transaction.objects.filter(
|
263
|
+
id__in=batch_ids
|
264
|
+
).delete()[0]
|
265
|
+
|
266
|
+
removed_count += deleted_count
|
267
|
+
|
268
|
+
if self.verbose:
|
269
|
+
self.stdout.write(f" Removed batch: {deleted_count} transactions")
|
270
|
+
|
271
|
+
# Update progress
|
272
|
+
progress = (removed_count / total_count) * 100
|
273
|
+
self.stdout.write(f"Progress: {removed_count}/{total_count} ({progress:.1f}%)")
|
274
|
+
|
275
|
+
self.stats['transactions_removed'] = removed_count
|
276
|
+
logger.info(f"Removed {removed_count} old transactions")
|
277
|
+
|
278
|
+
except Exception as e:
|
279
|
+
logger.error(f"Error cleaning up transactions: {e}")
|
280
|
+
self.stats['errors'] += 1
|
281
|
+
self.stdout.write(self.style.ERROR(f"Error: {e}"))
|
282
|
+
|
283
|
+
self.stdout.write("")
|
284
|
+
|
285
|
+
def cleanup_expired_api_keys(self):
|
286
|
+
"""Clean up expired API keys."""
|
287
|
+
self.stdout.write(self.style.SUCCESS("🔑 CLEANING UP EXPIRED API KEYS"))
|
288
|
+
self.stdout.write("-" * 40)
|
289
|
+
|
290
|
+
# Find expired API keys
|
291
|
+
now = timezone.now()
|
292
|
+
expired_keys = APIKey.objects.filter(
|
293
|
+
Q(expires_at__lt=now) | Q(is_active=False)
|
294
|
+
).filter(
|
295
|
+
# Only remove keys that haven't been used recently
|
296
|
+
last_used_at__lt=now - timedelta(days=7)
|
297
|
+
)
|
298
|
+
|
299
|
+
total_count = expired_keys.count()
|
300
|
+
self.stdout.write(f"Found {total_count} expired API keys to remove")
|
301
|
+
|
302
|
+
if total_count == 0:
|
303
|
+
self.stdout.write(self.style.WARNING("No expired API keys to clean up"))
|
304
|
+
return
|
305
|
+
|
306
|
+
if self.dry_run:
|
307
|
+
self.stdout.write(f"[DRY RUN] Would remove {total_count} expired API keys")
|
308
|
+
self.stats['api_keys_removed'] = total_count
|
309
|
+
return
|
310
|
+
|
311
|
+
try:
|
312
|
+
# Remove expired keys
|
313
|
+
removed_count = expired_keys.delete()[0]
|
314
|
+
self.stats['api_keys_removed'] = removed_count
|
315
|
+
|
316
|
+
self.stdout.write(f"Removed {removed_count} expired API keys")
|
317
|
+
logger.info(f"Removed {removed_count} expired API keys")
|
318
|
+
|
319
|
+
except Exception as e:
|
320
|
+
logger.error(f"Error cleaning up API keys: {e}")
|
321
|
+
self.stats['errors'] += 1
|
322
|
+
self.stdout.write(self.style.ERROR(f"Error: {e}"))
|
323
|
+
|
324
|
+
self.stdout.write("")
|
325
|
+
|
326
|
+
def cleanup_stale_cache(self):
|
327
|
+
"""Clean up stale cache entries."""
|
328
|
+
self.stdout.write(self.style.SUCCESS("💾 CLEANING UP STALE CACHE"))
|
329
|
+
self.stdout.write("-" * 40)
|
330
|
+
|
331
|
+
if self.dry_run:
|
332
|
+
self.stdout.write("[DRY RUN] Would clear stale cache entries")
|
333
|
+
self.stats['cache_entries_cleared'] = 100 # Estimate
|
334
|
+
return
|
335
|
+
|
336
|
+
try:
|
337
|
+
# Get cache service
|
338
|
+
cache_service = get_cache_service()
|
339
|
+
|
340
|
+
# Clear payment-related caches
|
341
|
+
cache_patterns = [
|
342
|
+
'payment:*',
|
343
|
+
'balance:*',
|
344
|
+
'api_key:*',
|
345
|
+
'currency:*',
|
346
|
+
'provider:*',
|
347
|
+
'rate_limit:*'
|
348
|
+
]
|
349
|
+
|
350
|
+
cleared_count = 0
|
351
|
+
|
352
|
+
for pattern in cache_patterns:
|
353
|
+
try:
|
354
|
+
# Clear cache entries matching pattern
|
355
|
+
if hasattr(cache_service, 'clear_pattern'):
|
356
|
+
count = cache_service.clear_pattern(pattern)
|
357
|
+
cleared_count += count
|
358
|
+
if self.verbose:
|
359
|
+
self.stdout.write(f" Cleared {count} entries for pattern: {pattern}")
|
360
|
+
except Exception as e:
|
361
|
+
logger.warning(f"Failed to clear cache pattern {pattern}: {e}")
|
362
|
+
|
363
|
+
# Fallback: clear all cache if pattern clearing not available
|
364
|
+
if cleared_count == 0:
|
365
|
+
cache.clear()
|
366
|
+
cleared_count = 1 # At least one operation
|
367
|
+
self.stdout.write("Cleared all cache entries")
|
368
|
+
|
369
|
+
self.stats['cache_entries_cleared'] = cleared_count
|
370
|
+
logger.info(f"Cleared {cleared_count} cache entries")
|
371
|
+
|
372
|
+
except Exception as e:
|
373
|
+
logger.error(f"Error cleaning up cache: {e}")
|
374
|
+
self.stats['errors'] += 1
|
375
|
+
self.stdout.write(self.style.ERROR(f"Error: {e}"))
|
376
|
+
|
377
|
+
self.stdout.write("")
|
378
|
+
|
379
|
+
def show_summary(self):
|
380
|
+
"""Display cleanup summary."""
|
381
|
+
self.stdout.write(self.style.SUCCESS("📊 CLEANUP SUMMARY"))
|
382
|
+
self.stdout.write("-" * 40)
|
383
|
+
|
384
|
+
summary_items = [
|
385
|
+
("Payments Removed", self.stats['payments_removed']),
|
386
|
+
("Transactions Removed", self.stats['transactions_removed']),
|
387
|
+
("API Keys Removed", self.stats['api_keys_removed']),
|
388
|
+
("Cache Entries Cleared", self.stats['cache_entries_cleared']),
|
389
|
+
("Errors", self.stats['errors']),
|
390
|
+
]
|
391
|
+
|
392
|
+
for label, count in summary_items:
|
393
|
+
if count > 0:
|
394
|
+
style = self.style.SUCCESS if label != "Errors" else self.style.ERROR
|
395
|
+
self.stdout.write(f"{label:<22}: {style(count)}")
|
396
|
+
|
397
|
+
# Calculate total items processed
|
398
|
+
total_processed = (
|
399
|
+
self.stats['payments_removed'] +
|
400
|
+
self.stats['transactions_removed'] +
|
401
|
+
self.stats['api_keys_removed']
|
402
|
+
)
|
403
|
+
|
404
|
+
if total_processed > 0:
|
405
|
+
self.stdout.write("")
|
406
|
+
self.stdout.write(f"Total items processed: {self.style.SUCCESS(total_processed)}")
|
407
|
+
|
408
|
+
# Show completion time
|
409
|
+
self.stdout.write("")
|
410
|
+
self.stdout.write(f"Completed: {timezone.now().strftime('%Y-%m-%d %H:%M:%S UTC')}")
|
411
|
+
|
412
|
+
# Show recommendations
|
413
|
+
if self.stats['errors'] > 0:
|
414
|
+
self.stdout.write("")
|
415
|
+
self.stdout.write(
|
416
|
+
self.style.WARNING("⚠️ Some cleanup operations had errors. Check logs for details.")
|
417
|
+
)
|
418
|
+
|
419
|
+
if total_processed == 0 and self.stats['errors'] == 0:
|
420
|
+
self.stdout.write("")
|
421
|
+
self.stdout.write(
|
422
|
+
self.style.SUCCESS("✅ No expired data found. System is clean!")
|
423
|
+
)
|
424
|
+
|
425
|
+
if self.dry_run and total_processed > 0:
|
426
|
+
self.stdout.write("")
|
427
|
+
self.stdout.write(
|
428
|
+
self.style.SUCCESS("✅ Dry run completed. Run without --dry-run to apply changes.")
|
429
|
+
)
|