Eluza133 commited on
Commit
8f2b70b
·
verified ·
1 Parent(s): 3f172be

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +70 -77
app.py CHANGED
@@ -13,16 +13,15 @@ from io import BytesIO
13
 
14
  app = Flask(__name__)
15
  app.secret_key = os.getenv("FLASK_SECRET_KEY", "supersecretkey")
16
- DATA_FILE = 'cloud_data.json'
17
  REPO_ID = "Eluza133/Z1e1u"
18
  HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
19
  HF_TOKEN_READ = os.getenv("HF_TOKEN_READ") or HF_TOKEN_WRITE
20
- REGISTRATION_CODE = "morshenalphacl"
21
 
22
  cache = Cache(app, config={'CACHE_TYPE': 'simple'})
23
  logging.basicConfig(level=logging.INFO)
24
 
25
- # Функции для работы с базой данных и Hugging Face
26
  @cache.memoize(timeout=300)
27
  def load_data():
28
  try:
@@ -30,14 +29,14 @@ def load_data():
30
  with open(DATA_FILE, 'r', encoding='utf-8') as file:
31
  data = json.load(file)
32
  if not isinstance(data, dict):
33
- logging.warning("Данные не в формате dict, инициализация пустой базы")
34
  return {'users': {}, 'files': {}}
35
  data.setdefault('users', {})
36
  data.setdefault('files', {})
37
- logging.info("Данные успешно загружены")
38
  return data
39
  except Exception as e:
40
- logging.error(f"Ошибка при загрузке данных: {e}")
41
  return {'users': {}, 'files': {}}
42
 
43
  def save_data(data):
@@ -46,9 +45,9 @@ def save_data(data):
46
  json.dump(data, file, ensure_ascii=False, indent=4)
47
  upload_db_to_hf()
48
  cache.clear()
49
- logging.info("Данные сохранены и загружены на HF")
50
  except Exception as e:
51
- logging.error(f"Ошибка при сохранении данных: {e}")
52
  raise
53
 
54
  def upload_db_to_hf():
@@ -60,11 +59,11 @@ def upload_db_to_hf():
60
  repo_id=REPO_ID,
61
  repo_type="dataset",
62
  token=HF_TOKEN_WRITE,
63
- commit_message=f"Бэкап {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
64
  )
65
- logging.info("База данных загружена на Hugging Face")
66
  except Exception as e:
67
- logging.error(f"Ошибка при загрузке базы данных: {e}")
68
 
69
  def download_db_from_hf():
70
  try:
@@ -76,9 +75,9 @@ def download_db_from_hf():
76
  local_dir=".",
77
  local_dir_use_symlinks=False
78
  )
79
- logging.info("База данных скачана с Hugging Face")
80
  except Exception as e:
81
- logging.error(f"Ошибка при скачивании базы данных: {e}")
82
  if not os.path.exists(DATA_FILE):
83
  with open(DATA_FILE, 'w', encoding='utf-8') as f:
84
  json.dump({'users': {}, 'files': {}}, f)
@@ -321,20 +320,15 @@ def register():
321
  if request.method == 'POST':
322
  username = request.form.get('username')
323
  password = request.form.get('password')
324
- code = request.form.get('code')
325
 
326
  data = load_data()
327
 
328
  if username in data['users']:
329
- flash('Пользователь с таким логином уже существует!')
330
- return redirect(url_for('register'))
331
-
332
- if code != REGISTRATION_CODE:
333
- flash('Неверный регистрационный код!')
334
  return redirect(url_for('register'))
335
 
336
  if not username or not password:
337
- flash('Логин и пароль обязательны!')
338
  return redirect(url_for('register'))
339
 
340
  data['users'][username] = {
@@ -344,7 +338,7 @@ def register():
344
  }
345
  save_data(data)
346
  session['username'] = username
347
- flash('Регистрация успешна!')
348
  return redirect(url_for('dashboard'))
349
 
350
  html = '''
@@ -353,13 +347,13 @@ def register():
353
  <head>
354
  <meta charset="UTF-8">
355
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
356
- <title>Регистрация - Zeus Cloud</title>
357
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap" rel="stylesheet">
358
  <style>''' + BASE_STYLE + '''</style>
359
  </head>
360
  <body>
361
  <div class="container">
362
- <h1>Регистрация в Zeus Cloud</h1>
363
  {% with messages = get_flashed_messages() %}
364
  {% if messages %}
365
  {% for message in messages %}
@@ -368,12 +362,11 @@ def register():
368
  {% endif %}
369
  {% endwith %}
370
  <form method="POST" id="register-form">
371
- <input type="text" name="username" placeholder="Введите логин" required>
372
- <input type="password" name="password" placeholder="Введите пароль" required>
373
- <input type="text" name="code" placeholder="Введите регистрационный код" required>
374
- <button type="submit" class="btn">Зарегистрироваться</button>
375
  </form>
376
- <p style="margin-top: 20px;">Уже есть аккаунт? <a href="{{ url_for('login') }}">Войдите</a></p>
377
  </div>
378
  </body>
379
  </html>
@@ -391,7 +384,7 @@ def login():
391
  session['username'] = username
392
  return jsonify({'status': 'success', 'redirect': url_for('dashboard')})
393
  else:
394
- return jsonify({'status': 'error', 'message': 'Неверный логин или пароль!'})
395
 
396
  html = '''
397
  <!DOCTYPE html>
@@ -416,14 +409,14 @@ def login():
416
  {% endwith %}
417
  </div>
418
  <form method="POST" id="login-form">
419
- <input type="text" name="username" placeholder="Введите логин" required>
420
- <input type="password" name="password" placeholder="Введите пароль" required>
421
- <button type="submit" class="btn">Войти</button>
422
  </form>
423
- <p style="margin-top: 20px;">Нет аккаунта? <a href="{{ url_for('register') }}">Зарегистрируйтесь</a></p>
424
  </div>
425
  <script>
426
- // Проверка localStorage и автоматический вход
427
  const savedCredentials = JSON.parse(localStorage.getItem('zeusCredentials'));
428
  if (savedCredentials) {
429
  fetch('/', {
@@ -439,10 +432,10 @@ def login():
439
  window.location.href = data.redirect;
440
  }
441
  })
442
- .catch(error => console.error('Ошибка автоматического входа:', error));
443
  }
444
 
445
- // Обработка формы входа
446
  document.getElementById('login-form').addEventListener('submit', function(e) {
447
  e.preventDefault();
448
  const formData = new FormData(this);
@@ -462,7 +455,7 @@ def login():
462
  }
463
  })
464
  .catch(error => {
465
- document.getElementById('flash-messages').innerHTML = `<div class="flash">Ошибка соединения!</div>`;
466
  });
467
  });
468
  </script>
@@ -474,14 +467,14 @@ def login():
474
  @app.route('/dashboard', methods=['GET', 'POST'])
475
  def dashboard():
476
  if 'username' not in session:
477
- flash('Пожалуйста, войдите!')
478
  return redirect(url_for('login'))
479
 
480
  username = session['username']
481
  data = load_data()
482
  if username not in data['users']:
483
  session.pop('username', None)
484
- flash('Пользователь не найден!')
485
  return redirect(url_for('login'))
486
 
487
  user_files = sorted(data['users'][username]['files'], key=lambda x: x['upload_date'], reverse=True)
@@ -489,7 +482,7 @@ def dashboard():
489
  if request.method == 'POST':
490
  files = request.files.getlist('files')
491
  if files and len(files) > 20:
492
- flash('Максимум 20 файлов за раз!')
493
  return redirect(url_for('dashboard'))
494
 
495
  if files:
@@ -512,7 +505,7 @@ def dashboard():
512
  repo_id=REPO_ID,
513
  repo_type="dataset",
514
  token=HF_TOKEN_WRITE,
515
- commit_message=f"Загружен файл для {username}"
516
  )
517
 
518
  file_info = {
@@ -527,7 +520,7 @@ def dashboard():
527
  os.remove(temp_path)
528
 
529
  save_data(data)
530
- flash('Файлы успешно загружены!')
531
 
532
  return redirect(url_for('dashboard'))
533
 
@@ -544,7 +537,7 @@ def dashboard():
544
  <body>
545
  <div class="container">
546
  <h1>Zeus Cloud Dashboard</h1>
547
- <p>Пользователь: {{ username }}</p>
548
  {% with messages = get_flashed_messages() %}
549
  {% if messages %}
550
  {% for message in messages %}
@@ -554,12 +547,12 @@ def dashboard():
554
  {% endwith %}
555
  <form id="upload-form" method="POST" enctype="multipart/form-data">
556
  <input type="file" name="files" multiple required accept="image/*,video/*">
557
- <button type="submit" class="btn" id="upload-btn">Загрузить файлы</button>
558
  </form>
559
  <div id="progress-container">
560
  <div id="progress-bar"></div>
561
  </div>
562
- <h2 style="margin-top: 30px;">Ваши файлы</h2>
563
  <div class="file-grid">
564
  {% for file in user_files %}
565
  <div class="file-item">
@@ -573,15 +566,15 @@ def dashboard():
573
  <p>{{ file['filename'] }}</p>
574
  {% endif %}
575
  <p>{{ file['upload_date'] }}</p>
576
- <a href="{{ url_for('download_file', file_path=file['path'], filename=file['filename']) }}" class="btn download-btn">Скачать</a>
577
- <a href="{{ url_for('delete_file', file_path=file['path']) }}" class="btn delete-btn" onclick="return confirm('Вы уверены, что хотите удалить этот файл?');">Удалить</a>
578
  </div>
579
  {% endfor %}
580
  {% if not user_files %}
581
- <p вас пока нет загруженных файлов.</p>
582
  {% endif %}
583
  </div>
584
- <a href="{{ url_for('logout') }}" class="btn" style="margin-top: 20px;" id="logout-btn">Выйти</a>
585
  </div>
586
  <div class="modal" id="mediaModal" onclick="closeModal(event)">
587
  <div id="modalContent"></div>
@@ -614,7 +607,7 @@ def dashboard():
614
  e.preventDefault();
615
  const files = form.querySelector('input[type="file"]').files;
616
  if (files.length > 20) {
617
- alert('Максимум 20 файлов за раз!');
618
  return;
619
  }
620
 
@@ -637,14 +630,14 @@ def dashboard():
637
  if (xhr.status === 200) {
638
  location.reload();
639
  } else {
640
- alert('Ошибка загрузки!');
641
  progressContainer.style.display = 'none';
642
  uploadBtn.disabled = false;
643
  }
644
  };
645
 
646
  xhr.onerror = function() {
647
- alert('Ошибка соединения!');
648
  progressContainer.style.display = 'none';
649
  uploadBtn.disabled = false;
650
  };
@@ -652,7 +645,7 @@ def dashboard():
652
  xhr.send(formData);
653
  });
654
 
655
- // Обработка выхода
656
  document.getElementById('logout-btn').addEventListener('click', function(e) {
657
  e.preventDefault();
658
  localStorage.removeItem('zeusCredentials');
@@ -667,19 +660,19 @@ def dashboard():
667
  @app.route('/download/<path:file_path>/<filename>')
668
  def download_file(file_path, filename):
669
  if 'username' not in session:
670
- flash('Пожалуйста, войдите!')
671
  return redirect(url_for('login'))
672
 
673
  username = session['username']
674
  data = load_data()
675
  if username not in data['users']:
676
  session.pop('username', None)
677
- flash('Пользователь не найден!')
678
  return redirect(url_for('login'))
679
 
680
  user_files = data['users'][username]['files']
681
  if not any(file['path'] == file_path for file in user_files):
682
- flash('У вас нет доступа к этому файлу!')
683
  return redirect(url_for('dashboard'))
684
 
685
  file_url = f"https://huggingface.co/datasets/{REPO_ID}/resolve/main/{file_path}"
@@ -694,27 +687,27 @@ def download_file(file_path, filename):
694
  mimetype='application/octet-stream'
695
  )
696
  else:
697
- flash('Ошибка при скачивании файла!')
698
  return redirect(url_for('dashboard'))
699
 
700
  @app.route('/delete/<path:file_path>')
701
  def delete_file(file_path):
702
  if 'username' not in session:
703
- flash('Пожалуйста, войдите!')
704
  return redirect(url_for('login'))
705
 
706
  username = session['username']
707
  data = load_data()
708
  if username not in data['users']:
709
  session.pop('username', None)
710
- flash('Пользователь не найден!')
711
  return redirect(url_for('login'))
712
 
713
  user_files = data['users'][username]['files']
714
  file_to_delete = next((file for file in user_files if file['path'] == file_path), None)
715
 
716
  if not file_to_delete:
717
- flash('Файл не найден!')
718
  return redirect(url_for('dashboard'))
719
 
720
  try:
@@ -724,14 +717,14 @@ def delete_file(file_path):
724
  repo_id=REPO_ID,
725
  repo_type="dataset",
726
  token=HF_TOKEN_WRITE,
727
- commit_message=f"Удален файл {file_path} для {username}"
728
  )
729
  data['users'][username]['files'] = [f for f in user_files if f['path'] != file_path]
730
  save_data(data)
731
- flash('Файл успешно удален!')
732
  except Exception as e:
733
- logging.error(f"Ошибка при удалении файла: {e}")
734
- flash('Ошибка при удалении файла!')
735
 
736
  return redirect(url_for('dashboard'))
737
 
@@ -740,7 +733,7 @@ def logout():
740
  session.pop('username', None)
741
  return redirect(url_for('login'))
742
 
743
- # Новая админ-панель
744
  @app.route('/admhosto')
745
  def admin_panel():
746
  data = load_data()
@@ -752,24 +745,24 @@ def admin_panel():
752
  <head>
753
  <meta charset="UTF-8">
754
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
755
- <title>Админ-панель - Zeus Cloud</title>
756
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap" rel="stylesheet">
757
  <style>''' + BASE_STYLE + '''</style>
758
  </head>
759
  <body>
760
  <div class="container">
761
- <h1>Админ-панель Zeus Cloud</h1>
762
- <h2>Список пользователей</h2>
763
  <div class="user-list">
764
  {% for username, user_data in users.items() %}
765
  <div class="user-item">
766
  <a href="{{ url_for('admin_user_files', username=username) }}">{{ username }}</a>
767
- <p>Дата регистрации: {{ user_data['created_at'] }}</p>
768
- <p>Количество файлов: {{ user_data['files'] | length }}</p>
769
  </div>
770
  {% endfor %}
771
  {% if not users %}
772
- <p>Пользователей пока нет.</p>
773
  {% endif %}
774
  </div>
775
  </div>
@@ -782,7 +775,7 @@ def admin_panel():
782
  def admin_user_files(username):
783
  data = load_data()
784
  if username not in data['users']:
785
- flash('Пользователь не найден!')
786
  return redirect(url_for('admin_panel'))
787
 
788
  user_files = sorted(data['users'][username]['files'], key=lambda x: x['upload_date'], reverse=True)
@@ -793,13 +786,13 @@ def admin_user_files(username):
793
  <head>
794
  <meta charset="UTF-8">
795
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
796
- <title>Файлы пользователя {{ username }} - Zeus Cloud</title>
797
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap" rel="stylesheet">
798
  <style>''' + BASE_STYLE + '''</style>
799
  </head>
800
  <body>
801
  <div class="container">
802
- <h1>Файлы пользователя: {{ username }}</h1>
803
  {% with messages = get_flashed_messages() %}
804
  {% if messages %}
805
  {% for message in messages %}
@@ -820,14 +813,14 @@ def admin_user_files(username):
820
  <p>{{ file['filename'] }}</p>
821
  {% endif %}
822
  <p>{{ file['upload_date'] }}</p>
823
- <a href="{{ url_for('download_file', file_path=file['path'], filename=file['filename']) }}" class="btn download-btn">Скачать</a>
824
  </div>
825
  {% endfor %}
826
  {% if not user_files %}
827
- <p пользователя пока нет файлов.</p>
828
  {% endif %}
829
  </div>
830
- <a href="{{ url_for('admin_panel') }}" class="btn" style="margin-top: 20px;">Назад к списку пользователей</a>
831
  </div>
832
  <div class="modal" id="mediaModal" onclick="closeModal(event)">
833
  <div id="modalContent"></div>
 
13
 
14
  app = Flask(__name__)
15
  app.secret_key = os.getenv("FLASK_SECRET_KEY", "supersecretkey")
16
+ DATA_FILE = 'cloudeng_data.json'
17
  REPO_ID = "Eluza133/Z1e1u"
18
  HF_TOKEN_WRITE = os.getenv("HF_TOKEN")
19
  HF_TOKEN_READ = os.getenv("HF_TOKEN_READ") or HF_TOKEN_WRITE
 
20
 
21
  cache = Cache(app, config={'CACHE_TYPE': 'simple'})
22
  logging.basicConfig(level=logging.INFO)
23
 
24
+ # Database and Hugging Face functions
25
  @cache.memoize(timeout=300)
26
  def load_data():
27
  try:
 
29
  with open(DATA_FILE, 'r', encoding='utf-8') as file:
30
  data = json.load(file)
31
  if not isinstance(data, dict):
32
+ logging.warning("Data is not in dict format, initializing empty database")
33
  return {'users': {}, 'files': {}}
34
  data.setdefault('users', {})
35
  data.setdefault('files', {})
36
+ logging.info("Data successfully loaded")
37
  return data
38
  except Exception as e:
39
+ logging.error(f"Error loading data: {e}")
40
  return {'users': {}, 'files': {}}
41
 
42
  def save_data(data):
 
45
  json.dump(data, file, ensure_ascii=False, indent=4)
46
  upload_db_to_hf()
47
  cache.clear()
48
+ logging.info("Data saved and uploaded to HF")
49
  except Exception as e:
50
+ logging.error(f"Error saving data: {e}")
51
  raise
52
 
53
  def upload_db_to_hf():
 
59
  repo_id=REPO_ID,
60
  repo_type="dataset",
61
  token=HF_TOKEN_WRITE,
62
+ commit_message=f"Backup {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
63
  )
64
+ logging.info("Database uploaded to Hugging Face")
65
  except Exception as e:
66
+ logging.error(f"Error uploading database: {e}")
67
 
68
  def download_db_from_hf():
69
  try:
 
75
  local_dir=".",
76
  local_dir_use_symlinks=False
77
  )
78
+ logging.info("Database downloaded from Hugging Face")
79
  except Exception as e:
80
+ logging.error(f"Error downloading database: {e}")
81
  if not os.path.exists(DATA_FILE):
82
  with open(DATA_FILE, 'w', encoding='utf-8') as f:
83
  json.dump({'users': {}, 'files': {}}, f)
 
320
  if request.method == 'POST':
321
  username = request.form.get('username')
322
  password = request.form.get('password')
 
323
 
324
  data = load_data()
325
 
326
  if username in data['users']:
327
+ flash('A user with this username already exists!')
 
 
 
 
328
  return redirect(url_for('register'))
329
 
330
  if not username or not password:
331
+ flash('Username and password are required!')
332
  return redirect(url_for('register'))
333
 
334
  data['users'][username] = {
 
338
  }
339
  save_data(data)
340
  session['username'] = username
341
+ flash('Registration successful!')
342
  return redirect(url_for('dashboard'))
343
 
344
  html = '''
 
347
  <head>
348
  <meta charset="UTF-8">
349
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
350
+ <title>Register - Zeus Cloud</title>
351
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap" rel="stylesheet">
352
  <style>''' + BASE_STYLE + '''</style>
353
  </head>
354
  <body>
355
  <div class="container">
356
+ <h1>Register in Zeus Cloud</h1>
357
  {% with messages = get_flashed_messages() %}
358
  {% if messages %}
359
  {% for message in messages %}
 
362
  {% endif %}
363
  {% endwith %}
364
  <form method="POST" id="register-form">
365
+ <input type="text" name="username" placeholder="Enter username" required>
366
+ <input type="password" name="password" placeholder="Enter password" required>
367
+ <button type="submit" class="btn">Register</button>
 
368
  </form>
369
+ <p style="margin-top: 20px;">Already have an account? <a href="{{ url_for('login') }}">Log in</a></p>
370
  </div>
371
  </body>
372
  </html>
 
384
  session['username'] = username
385
  return jsonify({'status': 'success', 'redirect': url_for('dashboard')})
386
  else:
387
+ return jsonify({'status': 'error', 'message': 'Invalid username or password!'})
388
 
389
  html = '''
390
  <!DOCTYPE html>
 
409
  {% endwith %}
410
  </div>
411
  <form method="POST" id="login-form">
412
+ <input type="text" name="username" placeholder="Enter username" required>
413
+ <input type="password" name="password" placeholder="Enter password" required>
414
+ <button type="submit" class="btn">Log in</button>
415
  </form>
416
+ <p style="margin-top: 20px;">No account? <a href="{{ url_for('register') }}">Register</a></p>
417
  </div>
418
  <script>
419
+ // Check localStorage and auto-login
420
  const savedCredentials = JSON.parse(localStorage.getItem('zeusCredentials'));
421
  if (savedCredentials) {
422
  fetch('/', {
 
432
  window.location.href = data.redirect;
433
  }
434
  })
435
+ .catch(error => console.error('Auto-login error:', error));
436
  }
437
 
438
+ // Handle login form submission
439
  document.getElementById('login-form').addEventListener('submit', function(e) {
440
  e.preventDefault();
441
  const formData = new FormData(this);
 
455
  }
456
  })
457
  .catch(error => {
458
+ document.getElementById('flash-messages').innerHTML = `<div class="flash">Connection error!</div>`;
459
  });
460
  });
461
  </script>
 
467
  @app.route('/dashboard', methods=['GET', 'POST'])
468
  def dashboard():
469
  if 'username' not in session:
470
+ flash('Please log in!')
471
  return redirect(url_for('login'))
472
 
473
  username = session['username']
474
  data = load_data()
475
  if username not in data['users']:
476
  session.pop('username', None)
477
+ flash('User not found!')
478
  return redirect(url_for('login'))
479
 
480
  user_files = sorted(data['users'][username]['files'], key=lambda x: x['upload_date'], reverse=True)
 
482
  if request.method == 'POST':
483
  files = request.files.getlist('files')
484
  if files and len(files) > 20:
485
+ flash('Maximum 20 files at a time!')
486
  return redirect(url_for('dashboard'))
487
 
488
  if files:
 
505
  repo_id=REPO_ID,
506
  repo_type="dataset",
507
  token=HF_TOKEN_WRITE,
508
+ commit_message=f"Uploaded file for {username}"
509
  )
510
 
511
  file_info = {
 
520
  os.remove(temp_path)
521
 
522
  save_data(data)
523
+ flash('Files uploaded successfully!')
524
 
525
  return redirect(url_for('dashboard'))
526
 
 
537
  <body>
538
  <div class="container">
539
  <h1>Zeus Cloud Dashboard</h1>
540
+ <p>User: {{ username }}</p>
541
  {% with messages = get_flashed_messages() %}
542
  {% if messages %}
543
  {% for message in messages %}
 
547
  {% endwith %}
548
  <form id="upload-form" method="POST" enctype="multipart/form-data">
549
  <input type="file" name="files" multiple required accept="image/*,video/*">
550
+ <button type="submit" class="btn" id="upload-btn">Upload Files</button>
551
  </form>
552
  <div id="progress-container">
553
  <div id="progress-bar"></div>
554
  </div>
555
+ <h2 style="margin-top: 30px;">Your Files</h2>
556
  <div class="file-grid">
557
  {% for file in user_files %}
558
  <div class="file-item">
 
566
  <p>{{ file['filename'] }}</p>
567
  {% endif %}
568
  <p>{{ file['upload_date'] }}</p>
569
+ <a href="{{ url_for('download_file', file_path=file['path'], filename=file['filename']) }}" class="btn download-btn">Download</a>
570
+ <a href="{{ url_for('delete_file', file_path=file['path']) }}" class="btn delete-btn" onclick="return confirm('Are you sure you want to delete this file?');">Delete</a>
571
  </div>
572
  {% endfor %}
573
  {% if not user_files %}
574
+ <p>You haven't uploaded any files yet.</p>
575
  {% endif %}
576
  </div>
577
+ <a href="{{ url_for('logout') }}" class="btn" style="margin-top: 20px;" id="logout-btn">Log out</a>
578
  </div>
579
  <div class="modal" id="mediaModal" onclick="closeModal(event)">
580
  <div id="modalContent"></div>
 
607
  e.preventDefault();
608
  const files = form.querySelector('input[type="file"]').files;
609
  if (files.length > 20) {
610
+ alert('Maximum 20 files at a time!');
611
  return;
612
  }
613
 
 
630
  if (xhr.status === 200) {
631
  location.reload();
632
  } else {
633
+ alert('Upload error!');
634
  progressContainer.style.display = 'none';
635
  uploadBtn.disabled = false;
636
  }
637
  };
638
 
639
  xhr.onerror = function() {
640
+ alert('Connection error!');
641
  progressContainer.style.display = 'none';
642
  uploadBtn.disabled = false;
643
  };
 
645
  xhr.send(formData);
646
  });
647
 
648
+ // Handle logout
649
  document.getElementById('logout-btn').addEventListener('click', function(e) {
650
  e.preventDefault();
651
  localStorage.removeItem('zeusCredentials');
 
660
  @app.route('/download/<path:file_path>/<filename>')
661
  def download_file(file_path, filename):
662
  if 'username' not in session:
663
+ flash('Please log in!')
664
  return redirect(url_for('login'))
665
 
666
  username = session['username']
667
  data = load_data()
668
  if username not in data['users']:
669
  session.pop('username', None)
670
+ flash('User not found!')
671
  return redirect(url_for('login'))
672
 
673
  user_files = data['users'][username]['files']
674
  if not any(file['path'] == file_path for file in user_files):
675
+ flash('You do not have access to this file!')
676
  return redirect(url_for('dashboard'))
677
 
678
  file_url = f"https://huggingface.co/datasets/{REPO_ID}/resolve/main/{file_path}"
 
687
  mimetype='application/octet-stream'
688
  )
689
  else:
690
+ flash('Error downloading file!')
691
  return redirect(url_for('dashboard'))
692
 
693
  @app.route('/delete/<path:file_path>')
694
  def delete_file(file_path):
695
  if 'username' not in session:
696
+ flash('Please log in!')
697
  return redirect(url_for('login'))
698
 
699
  username = session['username']
700
  data = load_data()
701
  if username not in data['users']:
702
  session.pop('username', None)
703
+ flash('User not found!')
704
  return redirect(url_for('login'))
705
 
706
  user_files = data['users'][username]['files']
707
  file_to_delete = next((file for file in user_files if file['path'] == file_path), None)
708
 
709
  if not file_to_delete:
710
+ flash('File not found!')
711
  return redirect(url_for('dashboard'))
712
 
713
  try:
 
717
  repo_id=REPO_ID,
718
  repo_type="dataset",
719
  token=HF_TOKEN_WRITE,
720
+ commit_message=f"Deleted file {file_path} for {username}"
721
  )
722
  data['users'][username]['files'] = [f for f in user_files if f['path'] != file_path]
723
  save_data(data)
724
+ flash('File deleted successfully!')
725
  except Exception as e:
726
+ logging.error(f"Error deleting file: {e}")
727
+ flash('Error deleting file!')
728
 
729
  return redirect(url_for('dashboard'))
730
 
 
733
  session.pop('username', None)
734
  return redirect(url_for('login'))
735
 
736
+ # Admin panel
737
  @app.route('/admhosto')
738
  def admin_panel():
739
  data = load_data()
 
745
  <head>
746
  <meta charset="UTF-8">
747
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
748
+ <title>Admin Panel - Zeus Cloud</title>
749
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap" rel="stylesheet">
750
  <style>''' + BASE_STYLE + '''</style>
751
  </head>
752
  <body>
753
  <div class="container">
754
+ <h1>Zeus Cloud Admin Panel</h1>
755
+ <h2>User List</h2>
756
  <div class="user-list">
757
  {% for username, user_data in users.items() %}
758
  <div class="user-item">
759
  <a href="{{ url_for('admin_user_files', username=username) }}">{{ username }}</a>
760
+ <p>Registration Date: {{ user_data['created_at'] }}</p>
761
+ <p>File Count: {{ user_data['files'] | length }}</p>
762
  </div>
763
  {% endfor %}
764
  {% if not users %}
765
+ <p>No users yet.</p>
766
  {% endif %}
767
  </div>
768
  </div>
 
775
  def admin_user_files(username):
776
  data = load_data()
777
  if username not in data['users']:
778
+ flash('User not found!')
779
  return redirect(url_for('admin_panel'))
780
 
781
  user_files = sorted(data['users'][username]['files'], key=lambda x: x['upload_date'], reverse=True)
 
786
  <head>
787
  <meta charset="UTF-8">
788
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
789
+ <title>User {{ username }} Files - Zeus Cloud</title>
790
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap" rel="stylesheet">
791
  <style>''' + BASE_STYLE + '''</style>
792
  </head>
793
  <body>
794
  <div class="container">
795
+ <h1>User Files: {{ username }}</h1>
796
  {% with messages = get_flashed_messages() %}
797
  {% if messages %}
798
  {% for message in messages %}
 
813
  <p>{{ file['filename'] }}</p>
814
  {% endif %}
815
  <p>{{ file['upload_date'] }}</p>
816
+ <a href="{{ url_for('download_file', file_path=file['path'], filename=file['filename']) }}" class="btn download-btn">Download</a>
817
  </div>
818
  {% endfor %}
819
  {% if not user_files %}
820
+ <p>This user has no files yet.</p>
821
  {% endif %}
822
  </div>
823
+ <a href="{{ url_for('admin_panel') }}" class="btn" style="margin-top: 20px;">Back to User List</a>
824
  </div>
825
  <div class="modal" id="mediaModal" onclick="closeModal(event)">
826
  <div id="modalContent"></div>