amauricunha commited on
Commit
fbaaaaf
·
verified ·
1 Parent(s): 317a9db

Delete admin_module.py

Browse files
Files changed (1) hide show
  1. admin_module.py +0 -524
admin_module.py DELETED
@@ -1,524 +0,0 @@
1
- # admin_module.py - Administrative interface for English Helper
2
- import os
3
- import json
4
- import hashlib
5
- from datetime import datetime, timedelta
6
- from functools import wraps
7
- from flask import session, request, jsonify, redirect, url_for
8
- import sqlite3
9
- from database import get_db_connection
10
- import logging
11
-
12
- logger = logging.getLogger(__name__)
13
-
14
- class AdminManager:
15
- def __init__(self):
16
- self.admin_credentials = self._load_admin_credentials()
17
- self.token_costs = {
18
- 'groq': {'input': 0.00000059, 'output': 0.00000079}, # per token
19
- 'gemini': {'input': 0.00000125, 'output': 0.00000375} # per token
20
- }
21
-
22
- def _load_admin_credentials(self):
23
- """Load admin credentials from environment variables (Hugging Face secrets)"""
24
- try:
25
- # Try to load from Hugging Face secrets format
26
- admin_user = os.environ.get('ADMIN_USERNAME', 'admin')
27
- admin_pass = os.environ.get('ADMIN_PASSWORD', 'admin123')
28
-
29
- # For security, hash the password
30
- admin_pass_hash = hashlib.sha256(admin_pass.encode()).hexdigest()
31
-
32
- return {
33
- 'username': admin_user,
34
- 'password_hash': admin_pass_hash,
35
- 'original_password': admin_pass # Store for initial comparison
36
- }
37
- except Exception as e:
38
- logger.error(f"Error loading admin credentials: {e}")
39
- # Fallback credentials
40
- return {
41
- 'username': 'admin',
42
- 'password_hash': hashlib.sha256('admin123'.encode()).hexdigest(),
43
- 'original_password': 'admin123'
44
- }
45
-
46
- def authenticate_admin(self, username, password):
47
- """Authenticate admin user"""
48
- try:
49
- if username != self.admin_credentials['username']:
50
- return False
51
-
52
- # Check password hash
53
- password_hash = hashlib.sha256(password.encode()).hexdigest()
54
- return password_hash == self.admin_credentials['password_hash']
55
- except Exception as e:
56
- logger.error(f"Admin authentication error: {e}")
57
- return False
58
-
59
- def is_admin_logged_in(self):
60
- """Check if admin is logged in"""
61
- return session.get('admin_authenticated', False)
62
-
63
- def login_admin(self, username, password):
64
- """Admin login"""
65
- if self.authenticate_admin(username, password):
66
- session['admin_authenticated'] = True
67
- session['admin_username'] = username
68
- session['admin_login_time'] = datetime.now().isoformat()
69
- return True
70
- return False
71
-
72
- def logout_admin(self):
73
- """Admin logout"""
74
- session.pop('admin_authenticated', None)
75
- session.pop('admin_username', None)
76
- session.pop('admin_login_time', None)
77
-
78
- def get_system_stats(self):
79
- """Get comprehensive system statistics"""
80
- try:
81
- conn = get_db_connection()
82
- cursor = conn.cursor()
83
-
84
- # User statistics
85
- cursor.execute("SELECT COUNT(*) FROM users")
86
- total_users = cursor.fetchone()[0]
87
-
88
- cursor.execute("SELECT COUNT(*) FROM users WHERE created_at > datetime('now', '-7 days')")
89
- new_users_week = cursor.fetchone()[0]
90
-
91
- cursor.execute("SELECT COUNT(*) FROM users WHERE created_at > datetime('now', '-1 day')")
92
- new_users_today = cursor.fetchone()[0]
93
-
94
- # Activity statistics
95
- cursor.execute("SELECT COUNT(*) FROM study_sessions")
96
- total_sessions = cursor.fetchone()[0]
97
-
98
- cursor.execute("SELECT COUNT(*) FROM flashcards")
99
- total_flashcards = cursor.fetchone()[0]
100
-
101
- cursor.execute("SELECT COUNT(*) FROM user_articles")
102
- total_articles = cursor.fetchone()[0]
103
-
104
- cursor.execute("SELECT COUNT(*) FROM study_plans")
105
- total_study_plans = cursor.fetchone()[0]
106
-
107
- # Token usage statistics
108
- cursor.execute("SELECT SUM(tokens_used), COUNT(*) FROM token_usage")
109
- token_stats = cursor.fetchone()
110
- total_tokens = token_stats[0] if token_stats[0] else 0
111
- total_api_calls = token_stats[1] if token_stats[1] else 0
112
-
113
- # Calculate estimated costs
114
- estimated_cost = self._calculate_estimated_cost(cursor)
115
-
116
- # Recent activity
117
- cursor.execute("""
118
- SELECT u.email, s.created_at, s.activity_type
119
- FROM study_sessions s
120
- JOIN users u ON s.user_id = u.id
121
- ORDER BY s.created_at DESC
122
- LIMIT 10
123
- """)
124
- recent_activity = cursor.fetchall()
125
-
126
- conn.close()
127
-
128
- return {
129
- 'users': {
130
- 'total': total_users,
131
- 'new_week': new_users_week,
132
- 'new_today': new_users_today
133
- },
134
- 'activity': {
135
- 'total_sessions': total_sessions,
136
- 'total_flashcards': total_flashcards,
137
- 'total_articles': total_articles,
138
- 'total_study_plans': total_study_plans
139
- },
140
- 'api_usage': {
141
- 'total_tokens': total_tokens,
142
- 'total_calls': total_api_calls,
143
- 'estimated_cost': estimated_cost
144
- },
145
- 'recent_activity': [
146
- {
147
- 'user': activity[0],
148
- 'timestamp': activity[1],
149
- 'activity': activity[2]
150
- } for activity in recent_activity
151
- ]
152
- }
153
- except Exception as e:
154
- logger.error(f"Error getting system stats: {e}")
155
- return {}
156
-
157
- def _calculate_estimated_cost(self, cursor):
158
- """Calculate estimated API costs"""
159
- try:
160
- cursor.execute("""
161
- SELECT api_provider, SUM(input_tokens), SUM(output_tokens)
162
- FROM token_usage
163
- GROUP BY api_provider
164
- """)
165
- usage_by_provider = cursor.fetchall()
166
-
167
- total_cost = 0
168
- for provider, input_tokens, output_tokens in usage_by_provider:
169
- if provider in self.token_costs:
170
- costs = self.token_costs[provider]
171
- total_cost += (input_tokens * costs['input']) + (output_tokens * costs['output'])
172
-
173
- return round(total_cost, 4)
174
- except:
175
- return 0
176
-
177
- def get_all_users(self, page=1, per_page=20):
178
- """Get paginated list of all users"""
179
- try:
180
- conn = get_db_connection()
181
- cursor = conn.cursor()
182
-
183
- offset = (page - 1) * per_page
184
-
185
- cursor.execute("""
186
- SELECT u.id, u.email, u.created_at, u.email_confirmed, u.last_login,
187
- COUNT(DISTINCT s.id) as session_count,
188
- COUNT(DISTINCT f.id) as flashcard_count,
189
- COUNT(DISTINCT a.id) as article_count
190
- FROM users u
191
- LEFT JOIN study_sessions s ON u.id = s.user_id
192
- LEFT JOIN flashcards f ON u.id = f.user_id
193
- LEFT JOIN user_articles a ON u.id = a.user_id
194
- GROUP BY u.id
195
- ORDER BY u.created_at DESC
196
- LIMIT ? OFFSET ?
197
- """, (per_page, offset))
198
-
199
- users = cursor.fetchall()
200
-
201
- # Get total count
202
- cursor.execute("SELECT COUNT(*) FROM users")
203
- total_users = cursor.fetchone()[0]
204
-
205
- conn.close()
206
-
207
- return {
208
- 'users': [
209
- {
210
- 'id': user[0],
211
- 'email': user[1],
212
- 'created_at': user[2],
213
- 'email_confirmed': bool(user[3]),
214
- 'last_login': user[4],
215
- 'session_count': user[5],
216
- 'flashcard_count': user[6],
217
- 'article_count': user[7]
218
- } for user in users
219
- ],
220
- 'total': total_users,
221
- 'page': page,
222
- 'per_page': per_page,
223
- 'total_pages': (total_users + per_page - 1) // per_page
224
- }
225
- except Exception as e:
226
- logger.error(f"Error getting users: {e}")
227
- return {'users': [], 'total': 0}
228
-
229
- def delete_user(self, user_id):
230
- """Delete a user and all associated data"""
231
- try:
232
- conn = get_db_connection()
233
- cursor = conn.cursor()
234
-
235
- # Delete in order to respect foreign key constraints
236
- tables = [
237
- 'study_plan_activities', 'study_plans', 'user_analytics',
238
- 'content_recommendations', 'user_interests', 'user_articles',
239
- 'study_sessions', 'flashcards', 'user_settings', 'users'
240
- ]
241
-
242
- for table in tables:
243
- cursor.execute(f"DELETE FROM {table} WHERE user_id = ?", (user_id,))
244
-
245
- conn.commit()
246
- conn.close()
247
-
248
- return True
249
- except Exception as e:
250
- logger.error(f"Error deleting user {user_id}: {e}")
251
- return False
252
-
253
- def get_user_details(self, user_id):
254
- """Get detailed information about a specific user"""
255
- try:
256
- conn = get_db_connection()
257
- cursor = conn.cursor()
258
-
259
- # Basic user info
260
- cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
261
- user = cursor.fetchone()
262
-
263
- if not user:
264
- return None
265
-
266
- # User settings
267
- cursor.execute("SELECT * FROM user_settings WHERE user_id = ?", (user_id,))
268
- settings = cursor.fetchone()
269
-
270
- # Recent activity
271
- cursor.execute("""
272
- SELECT activity_type, created_at, duration_minutes
273
- FROM study_sessions
274
- WHERE user_id = ?
275
- ORDER BY created_at DESC
276
- LIMIT 20
277
- """, (user_id,))
278
- recent_sessions = cursor.fetchall()
279
-
280
- # Token usage
281
- cursor.execute("""
282
- SELECT api_provider, SUM(input_tokens), SUM(output_tokens), COUNT(*)
283
- FROM token_usage
284
- WHERE user_id = ?
285
- GROUP BY api_provider
286
- """, (user_id,))
287
- token_usage = cursor.fetchall()
288
-
289
- conn.close()
290
-
291
- return {
292
- 'user': {
293
- 'id': user[0],
294
- 'email': user[1],
295
- 'created_at': user[2],
296
- 'email_confirmed': bool(user[3]),
297
- 'last_login': user[4]
298
- },
299
- 'settings': dict(zip([col[0] for col in cursor.description], settings)) if settings else {},
300
- 'recent_sessions': [
301
- {
302
- 'activity': session[0],
303
- 'timestamp': session[1],
304
- 'duration': session[2]
305
- } for session in recent_sessions
306
- ],
307
- 'token_usage': [
308
- {
309
- 'provider': usage[0],
310
- 'input_tokens': usage[1],
311
- 'output_tokens': usage[2],
312
- 'calls': usage[3]
313
- } for usage in token_usage
314
- ]
315
- }
316
- except Exception as e:
317
- logger.error(f"Error getting user details for {user_id}: {e}")
318
- return None
319
-
320
- def record_token_usage(self, user_id, api_provider, input_tokens, output_tokens, operation_type):
321
- """Record token usage for cost tracking"""
322
- try:
323
- conn = get_db_connection()
324
- cursor = conn.cursor()
325
-
326
- cursor.execute("""
327
- INSERT INTO token_usage
328
- (user_id, api_provider, input_tokens, output_tokens, operation_type, created_at)
329
- VALUES (?, ?, ?, ?, ?, ?)
330
- """, (user_id, api_provider, input_tokens, output_tokens, operation_type, datetime.now().isoformat()))
331
-
332
- conn.commit()
333
- conn.close()
334
-
335
- return True
336
- except Exception as e:
337
- logger.error(f"Error recording token usage: {e}")
338
- return False
339
-
340
- def get_database_schema(self):
341
- """Get database schema information"""
342
- try:
343
- conn = get_db_connection()
344
- cursor = conn.cursor()
345
-
346
- # Get all tables
347
- cursor.execute("SELECT name FROM sqlite_master WHERE type='table'")
348
- tables = cursor.fetchall()
349
-
350
- schema_info = {}
351
- for table in tables:
352
- table_name = table[0]
353
-
354
- # Get table info
355
- cursor.execute(f"PRAGMA table_info({table_name})")
356
- columns = cursor.fetchall()
357
-
358
- # Get row count
359
- cursor.execute(f"SELECT COUNT(*) FROM {table_name}")
360
- row_count = cursor.fetchone()[0]
361
-
362
- schema_info[table_name] = {
363
- 'columns': [
364
- {
365
- 'name': col[1],
366
- 'type': col[2],
367
- 'not_null': bool(col[3]),
368
- 'primary_key': bool(col[5])
369
- } for col in columns
370
- ],
371
- 'row_count': row_count
372
- }
373
-
374
- conn.close()
375
- return schema_info
376
- except Exception as e:
377
- logger.error(f"Error getting database schema: {e}")
378
- return {}
379
-
380
- def get_system_health(self):
381
- """Get system health metrics"""
382
- try:
383
- import psutil
384
- import os
385
-
386
- # Memory usage
387
- memory = psutil.virtual_memory()
388
-
389
- # Disk usage
390
- disk = psutil.disk_usage('/')
391
-
392
- # Database size
393
- db_path = 'data/englishhelper.db'
394
- db_size = os.path.getsize(db_path) if os.path.exists(db_path) else 0
395
-
396
- # Recent error logs (would implement proper logging)
397
- recent_errors = self._get_recent_errors()
398
-
399
- return {
400
- 'memory': {
401
- 'total': memory.total,
402
- 'used': memory.used,
403
- 'available': memory.available,
404
- 'percent': memory.percent
405
- },
406
- 'disk': {
407
- 'total': disk.total,
408
- 'used': disk.used,
409
- 'free': disk.free,
410
- 'percent': disk.percent
411
- },
412
- 'database': {
413
- 'size_bytes': db_size,
414
- 'size_mb': round(db_size / 1024 / 1024, 2)
415
- },
416
- 'recent_errors': recent_errors,
417
- 'uptime': self._get_uptime()
418
- }
419
- except Exception as e:
420
- logger.error(f"Error getting system health: {e}")
421
- return {}
422
-
423
- def _get_recent_errors(self):
424
- """Get recent error logs (simplified)"""
425
- try:
426
- # This would typically read from log files
427
- # For now, return sample data
428
- return [
429
- {
430
- 'timestamp': '2024-10-11 14:30:00',
431
- 'level': 'ERROR',
432
- 'message': 'API rate limit exceeded for user 123',
433
- 'module': 'groq_client'
434
- },
435
- {
436
- 'timestamp': '2024-10-11 13:45:00',
437
- 'level': 'WARNING',
438
- 'message': 'High memory usage detected',
439
- 'module': 'system_monitor'
440
- }
441
- ]
442
- except:
443
- return []
444
-
445
- def _get_uptime(self):
446
- """Get system uptime"""
447
- try:
448
- import psutil
449
- boot_time = psutil.boot_time()
450
- uptime_seconds = datetime.now().timestamp() - boot_time
451
-
452
- days = int(uptime_seconds // 86400)
453
- hours = int((uptime_seconds % 86400) // 3600)
454
- minutes = int((uptime_seconds % 3600) // 60)
455
-
456
- return f"{days}d {hours}h {minutes}m"
457
- except:
458
- return "Unknown"
459
-
460
- def check_system_alerts(self):
461
- """Check for system alerts and warnings"""
462
- alerts = []
463
-
464
- try:
465
- # Check token usage limits
466
- conn = get_db_connection()
467
- cursor = conn.cursor()
468
-
469
- # Check daily token usage
470
- cursor.execute("""
471
- SELECT SUM(tokens_used)
472
- FROM token_usage
473
- WHERE date(created_at) = date('now')
474
- """)
475
- daily_tokens = cursor.fetchone()[0] or 0
476
-
477
- if daily_tokens > 100000: # Alert threshold
478
- alerts.append({
479
- 'type': 'warning',
480
- 'message': f'High daily token usage: {daily_tokens:,} tokens',
481
- 'action': 'Monitor API costs'
482
- })
483
-
484
- # Check error rates
485
- cursor.execute("""
486
- SELECT COUNT(*) FROM token_usage
487
- WHERE created_at > datetime('now', '-1 hour')
488
- """)
489
- hourly_requests = cursor.fetchone()[0] or 0
490
-
491
- if hourly_requests > 500: # High load threshold
492
- alerts.append({
493
- 'type': 'info',
494
- 'message': f'High API request rate: {hourly_requests} requests/hour',
495
- 'action': 'Monitor performance'
496
- })
497
-
498
- # Check database size
499
- health = self.get_system_health()
500
- if health.get('database', {}).get('size_mb', 0) > 100: # 100MB threshold
501
- alerts.append({
502
- 'type': 'warning',
503
- 'message': f'Large database size: {health["database"]["size_mb"]}MB',
504
- 'action': 'Consider archiving old data'
505
- })
506
-
507
- conn.close()
508
- return alerts
509
-
510
- except Exception as e:
511
- logger.error(f"Error checking system alerts: {e}")
512
- return []
513
-
514
- # Decorator for admin-only routes
515
- def admin_required(f):
516
- @wraps(f)
517
- def decorated_function(*args, **kwargs):
518
- if not admin_manager.is_admin_logged_in():
519
- return jsonify({'error': 'Admin authentication required'}), 401
520
- return f(*args, **kwargs)
521
- return decorated_function
522
-
523
- # Global admin manager instance
524
- admin_manager = AdminManager()