Eluza133 commited on
Commit
0825176
·
verified ·
1 Parent(s): fe46f53

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +105 -111
app.py CHANGED
@@ -18,7 +18,6 @@ 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
- ADMIN_PASSWORD = "admin123" # Установите надежный пароль для админ-панели
22
 
23
  cache = Cache(app, config={'CACHE_TYPE': 'simple'})
24
  logging.basicConfig(level=logging.INFO)
@@ -145,6 +144,14 @@ h1 {
145
  -webkit-background-clip: text;
146
  color: transparent;
147
  }
 
 
 
 
 
 
 
 
148
  input, textarea {
149
  width: 100%;
150
  padding: 14px;
@@ -183,41 +190,39 @@ input:focus, textarea:focus {
183
  }
184
  .download-btn {
185
  background: var(--secondary);
186
- color: #ffffff;
187
  margin-top: 10px;
188
  }
189
  .download-btn:hover {
190
  background: #00b8c5;
191
- color: #ffffff;
192
  }
193
  .delete-btn {
194
  background: var(--delete-color);
195
- color: #ffffff;
196
  margin-top: 10px;
197
  }
198
  .delete-btn:hover {
199
  background: #cc3333;
200
- color: #ffffff;
201
  }
202
  .flash {
203
  color: var(--secondary);
204
  text-align: center;
205
  margin-bottom: 15px;
206
  }
207
- .file-grid, .user-grid {
208
  display: grid;
209
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
210
  gap: 20px;
211
  margin-top: 20px;
212
  }
 
 
 
213
  .user-item {
214
- background: var(--card-bg);
215
  padding: 15px;
 
216
  border-radius: 16px;
 
217
  box-shadow: var(--shadow);
218
- text-align: center;
219
  transition: var(--transition);
220
- cursor: pointer;
221
  }
222
  body.dark .user-item {
223
  background: var(--card-bg-dark);
@@ -225,6 +230,24 @@ body.dark .user-item {
225
  .user-item:hover {
226
  transform: translateY(-5px);
227
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
  .file-item {
229
  background: var(--card-bg);
230
  padding: 15px;
@@ -232,7 +255,6 @@ body.dark .user-item {
232
  box-shadow: var(--shadow);
233
  text-align: center;
234
  transition: var(--transition);
235
- display: none; /* Скрыто по умолчанию */
236
  }
237
  body.dark .file-item {
238
  background: var(--card-bg-dark);
@@ -248,15 +270,15 @@ body.dark .file-item {
248
  margin-bottom: 10px;
249
  loading: lazy;
250
  }
251
- .file-item p, .user-item p {
252
  font-size: 0.9em;
253
  margin: 5px 0;
254
  }
255
- .file-item a, .user-item a {
256
  color: var(--primary);
257
  text-decoration: none;
258
  }
259
- .file-item a:hover, .user-item a:hover {
260
  color: var(--accent);
261
  }
262
  .modal {
@@ -292,24 +314,6 @@ body.dark .file-item {
292
  border-radius: 10px;
293
  transition: width 0.3s ease;
294
  }
295
- #search-bar {
296
- width: 100%;
297
- padding: 10px;
298
- margin: 10px 0;
299
- border: none;
300
- border-radius: 14px;
301
- background: var(--glass-bg);
302
- color: var(--text-light);
303
- font-size: 1.1em;
304
- box-shadow: inset 0 3px 10px rgba(0, 0, 0, 0.1);
305
- }
306
- body.dark #search-bar {
307
- color: var(--text-dark);
308
- }
309
- #search-bar:focus {
310
- outline: none;
311
- box-shadow: 0 0 0 4px var(--primary);
312
- }
313
  '''
314
 
315
  @app.route('/register', methods=['GET', 'POST'])
@@ -417,9 +421,9 @@ def login():
417
  <button type="submit" class="btn">Войти</button>
418
  </form>
419
  <p style="margin-top: 20px;">Нет аккаунта? <a href="{{ url_for('register') }}">Зарегистрируйтесь</a></p>
420
- <p style="margin-top: 10px;"><a href="{{ url_for('admhosto') }}">Админ-панель</a></p>
421
  </div>
422
  <script>
 
423
  const savedCredentials = JSON.parse(localStorage.getItem('zeusCredentials'));
424
  if (savedCredentials) {
425
  fetch('/', {
@@ -438,6 +442,7 @@ def login():
438
  .catch(error => console.error('Ошибка автоматического входа:', error));
439
  }
440
 
 
441
  document.getElementById('login-form').addEventListener('submit', function(e) {
442
  e.preventDefault();
443
  const formData = new FormData(this);
@@ -647,6 +652,7 @@ def dashboard():
647
  xhr.send(formData);
648
  });
649
 
 
650
  document.getElementById('logout-btn').addEventListener('click', function(e) {
651
  e.preventDefault();
652
  localStorage.removeItem('zeusCredentials');
@@ -729,18 +735,18 @@ def delete_file(file_path):
729
 
730
  return redirect(url_for('dashboard'))
731
 
732
- @app.route('/admhosto', methods=['GET', 'POST'])
733
- def admhosto():
734
- if request.method == 'POST':
735
- admin_password = request.form.get('admin_password')
736
- if admin_password != ADMIN_PASSWORD:
737
- flash('Неверный пароль администратора!')
738
- return redirect(url_for('admhosto'))
739
- session['is_admin'] = True
740
- return redirect(url_for('admhosto'))
741
 
742
- if 'is_admin' not in session:
743
- html = '''
 
 
 
 
 
744
  <!DOCTYPE html>
745
  <html lang="en">
746
  <head>
@@ -753,39 +759,47 @@ def admhosto():
753
  <body>
754
  <div class="container">
755
  <h1>Админ-панель Zeus Cloud</h1>
756
- {% with messages = get_flashed_messages() %}
757
- {% if messages %}
758
- {% for message in messages %}
759
- <div class="flash">{{ message }}</div>
760
- {% endfor %}
 
 
 
 
 
 
761
  {% endif %}
762
- {% endwith %}
763
- <form method="POST">
764
- <input type="password" name="admin_password" placeholder="Введите пароль администратора" required>
765
- <button type="submit" class="btn">Войти</button>
766
- </form>
767
  </div>
768
  </body>
769
  </html>
770
  '''
771
- return render_template_string(html)
772
 
 
 
773
  data = load_data()
774
- users = data['users']
775
-
 
 
 
 
776
  html = '''
777
  <!DOCTYPE html>
778
  <html lang="en">
779
  <head>
780
  <meta charset="UTF-8">
781
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
782
- <title>Админ-панель - Zeus Cloud</title>
783
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap" rel="stylesheet">
784
  <style>''' + BASE_STYLE + '''</style>
785
  </head>
786
  <body>
787
  <div class="container">
788
- <h1>Админ-панель Zeus Cloud</h1>
789
  {% with messages = get_flashed_messages() %}
790
  {% if messages %}
791
  {% for message in messages %}
@@ -793,74 +807,54 @@ def admhosto():
793
  {% endfor %}
794
  {% endif %}
795
  {% endwith %}
796
- <input type="text" id="search-bar" placeholder="Поиск по пользователям..." onkeyup="searchUsers()">
797
- <div class="user-grid">
798
- {% for username in users.keys() %}
799
- <div class="user-item" onclick="toggleFiles('{{ username }}')">
800
- <p>Пользователь: {{ username }}</p>
801
- <p>Дата регистрации: {{ users[username]['created_at'] }}</p>
802
- </div>
803
- <div id="files-{{ username }}" class="file-grid">
804
- {% for file in users[username]['files'] %}
805
- <div class="file-item">
806
- {% if file['type'] == 'video' %}
807
- <p>{{ file['filename'] }} (Video)</p>
808
- {% elif file['type'] == 'image' %}
809
- <p>{{ file['filename'] }} (Image)</p>
810
- {% else %}
811
- <p>{{ file['filename'] }}</p>
812
- {% endif %}
813
- <p>{{ file['upload_date'] }}</p>
814
- </div>
815
- {% endfor %}
816
- {% if not users[username]['files'] %}
817
- <p>Нет файлов</p>
818
  {% endif %}
 
 
819
  </div>
820
  {% endfor %}
 
 
 
821
  </div>
822
- <a href="{{ url_for('logout_admin') }}" class="btn" style="margin-top: 20px;">Выйти</a>
 
 
 
823
  </div>
824
  <script>
825
- function toggleFiles(username) {
826
- const filesDiv = document.getElementById(`files-${username}`);
827
- if (filesDiv.style.display === 'none' || filesDiv.style.display === '') {
828
- filesDiv.style.display = 'grid';
 
829
  } else {
830
- filesDiv.style.display = 'none';
831
  }
 
832
  }
833
-
834
- function searchUsers() {
835
- const input = document.getElementById('search-bar').value.toLowerCase();
836
- const userItems = document.getElementsByClassName('user-item');
837
-
838
- for (let i = 0; i < userItems.length; i++) {
839
- const username = userItems[i].getElementsByTagName('p')[0].textContent.toLowerCase().replace('Пользователь: ', '');
840
- if (username.includes(input)) {
841
- userItems[i].style.display = '';
842
- userItems[i].nextElementSibling.style.display = 'none'; // Скрываем файлы при поиске
843
- } else {
844
- userItems[i].style.display = 'none';
845
- userItems[i].nextElementSibling.style.display = 'none';
846
- }
847
  }
848
  }
849
  </script>
850
  </body>
851
  </html>
852
  '''
853
- return render_template_string(html, users=users)
854
-
855
- @app.route('/logout_admin')
856
- def logout_admin():
857
- session.pop('is_admin', None)
858
- return redirect(url_for('admhosto'))
859
-
860
- @app.route('/logout')
861
- def logout():
862
- session.pop('username', None)
863
- return redirect(url_for('login'))
864
 
865
  if __name__ == '__main__':
866
  threading.Thread(target=periodic_backup, daemon=True).start()
 
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)
 
144
  -webkit-background-clip: text;
145
  color: transparent;
146
  }
147
+ h2 {
148
+ font-size: 1.5em;
149
+ margin-top: 30px;
150
+ color: var(--text-light);
151
+ }
152
+ body.dark h2 {
153
+ color: var(--text-dark);
154
+ }
155
  input, textarea {
156
  width: 100%;
157
  padding: 14px;
 
190
  }
191
  .download-btn {
192
  background: var(--secondary);
 
193
  margin-top: 10px;
194
  }
195
  .download-btn:hover {
196
  background: #00b8c5;
 
197
  }
198
  .delete-btn {
199
  background: var(--delete-color);
 
200
  margin-top: 10px;
201
  }
202
  .delete-btn:hover {
203
  background: #cc3333;
 
204
  }
205
  .flash {
206
  color: var(--secondary);
207
  text-align: center;
208
  margin-bottom: 15px;
209
  }
210
+ .file-grid {
211
  display: grid;
212
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
213
  gap: 20px;
214
  margin-top: 20px;
215
  }
216
+ .user-list {
217
+ margin-top: 20px;
218
+ }
219
  .user-item {
 
220
  padding: 15px;
221
+ background: var(--card-bg);
222
  border-radius: 16px;
223
+ margin-bottom: 10px;
224
  box-shadow: var(--shadow);
 
225
  transition: var(--transition);
 
226
  }
227
  body.dark .user-item {
228
  background: var(--card-bg-dark);
 
230
  .user-item:hover {
231
  transform: translateY(-5px);
232
  }
233
+ .user-item a {
234
+ color: var(--primary);
235
+ text-decoration: none;
236
+ font-weight: 600;
237
+ }
238
+ .user-item a:hover {
239
+ color: var(--accent);
240
+ }
241
+ @media (max-width: 768px) {
242
+ .file-grid {
243
+ grid-template-columns: repeat(2, 1fr);
244
+ }
245
+ }
246
+ @media (max-width: 480px) {
247
+ .file-grid {
248
+ grid-template-columns: 1fr;
249
+ }
250
+ }
251
  .file-item {
252
  background: var(--card-bg);
253
  padding: 15px;
 
255
  box-shadow: var(--shadow);
256
  text-align: center;
257
  transition: var(--transition);
 
258
  }
259
  body.dark .file-item {
260
  background: var(--card-bg-dark);
 
270
  margin-bottom: 10px;
271
  loading: lazy;
272
  }
273
+ .file-item p {
274
  font-size: 0.9em;
275
  margin: 5px 0;
276
  }
277
+ .file-item a {
278
  color: var(--primary);
279
  text-decoration: none;
280
  }
281
+ .file-item a:hover {
282
  color: var(--accent);
283
  }
284
  .modal {
 
314
  border-radius: 10px;
315
  transition: width 0.3s ease;
316
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
  '''
318
 
319
  @app.route('/register', methods=['GET', 'POST'])
 
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('/', {
 
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);
 
652
  xhr.send(formData);
653
  });
654
 
655
+ // Обработка выхода
656
  document.getElementById('logout-btn').addEventListener('click', function(e) {
657
  e.preventDefault();
658
  localStorage.removeItem('zeusCredentials');
 
735
 
736
  return redirect(url_for('dashboard'))
737
 
738
+ @app.route('/logout')
739
+ 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()
747
+ users = data['users']
748
+
749
+ html = '''
750
  <!DOCTYPE html>
751
  <html lang="en">
752
  <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>
776
  </body>
777
  </html>
778
  '''
779
+ return render_template_string(html, users=users)
780
 
781
+ @app.route('/admhosto/user/<username>')
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)
789
+
790
  html = '''
791
  <!DOCTYPE html>
792
  <html lang="en">
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 %}
 
807
  {% endfor %}
808
  {% endif %}
809
  {% endwith %}
810
+ <div class="file-grid">
811
+ {% for file in user_files %}
812
+ <div class="file-item">
813
+ {% if file['type'] == 'video' %}
814
+ <video class="file-preview" preload="metadata" muted loading="lazy" onclick="openModal('https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ file['path'] }}', true)">
815
+ <source src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ file['path'] }}" type="video/mp4">
816
+ </video>
817
+ {% elif file['type'] == 'image' %}
818
+ <img class="file-preview" src="https://huggingface.co/datasets/{{ repo_id }}/resolve/main/{{ file['path'] }}" alt="{{ file['filename'] }}" loading="lazy" onclick="openModal(this.src, false)">
819
+ {% else %}
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>
834
  </div>
835
  <script>
836
+ function openModal(src, isVideo) {
837
+ const modal = document.getElementById('mediaModal');
838
+ const modalContent = document.getElementById('modalContent');
839
+ if (isVideo) {
840
+ modalContent.innerHTML = `<video controls><source src="${src}" type="video/mp4"></video>`;
841
  } else {
842
+ modalContent.innerHTML = `<img src="${src}">`;
843
  }
844
+ modal.style.display = 'flex';
845
  }
846
+ function closeModal(event) {
847
+ if (event.target.tagName !== 'IMG' && event.target.tagName !== 'VIDEO') {
848
+ const modal = document.getElementById('mediaModal');
849
+ modal.style.display = 'none';
850
+ modal.innerHTML = '<div id="modalContent"></div>';
 
 
 
 
 
 
 
 
 
851
  }
852
  }
853
  </script>
854
  </body>
855
  </html>
856
  '''
857
+ return render_template_string(html, username=username, user_files=user_files, repo_id=REPO_ID)
 
 
 
 
 
 
 
 
 
 
858
 
859
  if __name__ == '__main__':
860
  threading.Thread(target=periodic_backup, daemon=True).start()