Update app.py
Browse files
app.py
CHANGED
|
@@ -144,6 +144,14 @@ h1 {
|
|
| 144 |
-webkit-background-clip: text;
|
| 145 |
color: transparent;
|
| 146 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 147 |
input, textarea {
|
| 148 |
width: 100%;
|
| 149 |
padding: 14px;
|
|
@@ -205,6 +213,31 @@ input:focus, textarea:focus {
|
|
| 205 |
gap: 20px;
|
| 206 |
margin-top: 20px;
|
| 207 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 208 |
@media (max-width: 768px) {
|
| 209 |
.file-grid {
|
| 210 |
grid-template-columns: repeat(2, 1fr);
|
|
@@ -707,6 +740,122 @@ def logout():
|
|
| 707 |
session.pop('username', None)
|
| 708 |
return redirect(url_for('login'))
|
| 709 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 710 |
if __name__ == '__main__':
|
| 711 |
threading.Thread(target=periodic_backup, daemon=True).start()
|
| 712 |
app.run(debug=True, host='0.0.0.0', port=7860)
|
|
|
|
| 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;
|
|
|
|
| 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);
|
| 229 |
+
}
|
| 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);
|
|
|
|
| 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>
|
| 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>
|
| 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 %}
|
| 806 |
+
<div class="flash">{{ message }}</div>
|
| 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()
|
| 861 |
app.run(debug=True, host='0.0.0.0', port=7860)
|