228 lines
7.2 KiB
HTML
228 lines
7.2 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}My Files - Das File Storage{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="nav-tabs">
|
|
<a href="/dashboard" class="nav-tab active">📂 My Files</a>
|
|
<a href="/settings" class="nav-tab">⚙️ Settings</a>
|
|
{% if is_admin %}
|
|
<a href="/admin" class="nav-tab">👑 Admin Panel</a>
|
|
{% endif %}
|
|
</div>
|
|
|
|
{% if message %}
|
|
<div class="alert alert-success">
|
|
{{ message }}
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if error %}
|
|
<div class="alert alert-error">
|
|
{{ error }}
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
|
|
<h2>My Files</h2>
|
|
<button onclick="openUploadModal()" class="btn btn-primary">
|
|
⬆️ Upload File
|
|
</button>
|
|
</div>
|
|
|
|
{% if files %}
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Filename</th>
|
|
<th>Size</th>
|
|
<th>Uploaded</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for file in files %}
|
|
<tr>
|
|
<td>
|
|
<strong>{{ file.filename }}</strong>
|
|
<div class="file-size">{{ file.content_type or 'Unknown' }}</div>
|
|
</td>
|
|
<td class="file-size">{{ format_size(file.file_size) }}</td>
|
|
<td class="file-size">{{ file.uploaded_at.strftime('%Y-%m-%d %H:%M') }}</td>
|
|
<td>
|
|
<button onclick="downloadFile({{ file.id }}, '{{ file.filename }}')" class="btn btn-primary btn-small">
|
|
⬇️ Download
|
|
</button>
|
|
<button onclick="showShareLink('{{ file.share_token }}')" class="btn btn-success btn-small">
|
|
🔗 Share
|
|
</button>
|
|
<button onclick="deleteFile({{ file.id }}, '{{ file.filename }}')" class="btn btn-danger btn-small">
|
|
🗑️ Delete
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
{% else %}
|
|
<div class="empty-state">
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" />
|
|
</svg>
|
|
<h3>No files yet</h3>
|
|
<p>Upload your first file to get started</p>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Upload Modal -->
|
|
<div id="uploadModal" class="modal">
|
|
<div class="modal-content">
|
|
<div class="modal-header">Upload File</div>
|
|
<form id="uploadForm" enctype="multipart/form-data">
|
|
<div class="form-group">
|
|
<label for="fileInput">Choose file</label>
|
|
<input type="file" id="fileInput" name="file" required>
|
|
</div>
|
|
<div class="form-actions">
|
|
<button type="button" onclick="closeUploadModal()" class="btn btn-secondary">Cancel</button>
|
|
<button type="submit" class="btn btn-primary">Upload</button>
|
|
</div>
|
|
</form>
|
|
<div id="uploadProgress" style="display: none; margin-top: 20px;">
|
|
<div style="background: #e5e7eb; height: 20px; border-radius: 10px; overflow: hidden;">
|
|
<div id="progressBar" style="background: #667eea; height: 100%; width: 0%; transition: width 0.3s;"></div>
|
|
</div>
|
|
<p style="text-align: center; margin-top: 10px; color: #6b7280;">Uploading...</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Share Modal -->
|
|
<div id="shareModal" class="modal">
|
|
<div class="modal-content">
|
|
<div class="modal-header">Share File</div>
|
|
<p style="margin-bottom: 15px; color: #6b7280;">Anyone with this link can download the file:</p>
|
|
<div class="share-link">
|
|
<input type="text" id="shareLink" readonly>
|
|
<button onclick="copyShareLink()" class="btn btn-primary btn-small">📋 Copy</button>
|
|
</div>
|
|
<div class="form-actions" style="margin-top: 20px;">
|
|
<button onclick="closeShareModal()" class="btn btn-secondary">Close</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% endblock %}
|
|
|
|
{% block extra_scripts %}
|
|
<script>
|
|
function openUploadModal() {
|
|
document.getElementById('uploadModal').classList.add('active');
|
|
}
|
|
|
|
function closeUploadModal() {
|
|
document.getElementById('uploadModal').classList.remove('active');
|
|
document.getElementById('uploadForm').reset();
|
|
document.getElementById('uploadProgress').style.display = 'none';
|
|
}
|
|
|
|
document.getElementById('uploadForm').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
|
|
const fileInput = document.getElementById('fileInput');
|
|
const file = fileInput.files[0];
|
|
|
|
if (!file) return;
|
|
|
|
const formData = new FormData();
|
|
formData.append('file', file);
|
|
|
|
document.getElementById('uploadProgress').style.display = 'block';
|
|
|
|
try {
|
|
const response = await fetch('/api/files/upload', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
|
|
if (response.ok) {
|
|
window.location.reload();
|
|
} else {
|
|
const error = await response.json();
|
|
alert('Upload failed: ' + (error.detail || 'Unknown error'));
|
|
document.getElementById('uploadProgress').style.display = 'none';
|
|
}
|
|
} catch (error) {
|
|
alert('Upload failed: ' + error.message);
|
|
document.getElementById('uploadProgress').style.display = 'none';
|
|
}
|
|
});
|
|
|
|
async function downloadFile(fileId, filename) {
|
|
try {
|
|
const response = await fetch(`/api/files/${fileId}/download`);
|
|
if (response.ok) {
|
|
const blob = await response.blob();
|
|
const url = window.URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = filename;
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
window.URL.revokeObjectURL(url);
|
|
document.body.removeChild(a);
|
|
} else {
|
|
alert('Download failed');
|
|
}
|
|
} catch (error) {
|
|
alert('Download failed: ' + error.message);
|
|
}
|
|
}
|
|
|
|
function showShareLink(shareToken) {
|
|
const shareLink = window.location.origin + '/share/' + shareToken;
|
|
document.getElementById('shareLink').value = shareLink;
|
|
document.getElementById('shareModal').classList.add('active');
|
|
}
|
|
|
|
function closeShareModal() {
|
|
document.getElementById('shareModal').classList.remove('active');
|
|
}
|
|
|
|
function copyShareLink() {
|
|
const input = document.getElementById('shareLink');
|
|
input.select();
|
|
document.execCommand('copy');
|
|
alert('Link copied to clipboard!');
|
|
}
|
|
|
|
async function deleteFile(fileId, filename) {
|
|
if (!confirm(`Are you sure you want to delete "${filename}"?`)) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(`/api/files/${fileId}`, {
|
|
method: 'DELETE'
|
|
});
|
|
|
|
if (response.ok) {
|
|
window.location.reload();
|
|
} else {
|
|
alert('Delete failed');
|
|
}
|
|
} catch (error) {
|
|
alert('Delete failed: ' + error.message);
|
|
}
|
|
}
|
|
|
|
// Close modals when clicking outside
|
|
document.querySelectorAll('.modal').forEach(modal => {
|
|
modal.addEventListener('click', (e) => {
|
|
if (e.target === modal) {
|
|
modal.classList.remove('active');
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %} |