Upload files to "templates"
This commit is contained in:
parent
752c925611
commit
efce5ec6ab
|
|
@ -0,0 +1,40 @@
|
|||
<!-- templates/base.html -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}Flask NEO Storage{% endblock %}</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="/">NEO Storage Demo</a>
|
||||
<div class="navbar-nav">
|
||||
<a class="nav-link" href="/">Home</a>
|
||||
<a class="nav-link" href="/upload">Upload</a>
|
||||
<a class="nav-link" href="/files">Files</a>
|
||||
<a class="nav-link" href="/test-connection">Test</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div class="alert alert-{{ 'danger' if category == 'error' else 'success' }} alert-dismissible fade show">
|
||||
{{ message }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
|
||||
<!-- templates/files.html -->
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Files - Flask NEO Storage{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>Files di NEO Object Storage</h2>
|
||||
<a href="/upload" class="btn btn-primary">Upload File Baru</a>
|
||||
</div>
|
||||
|
||||
{% if files %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Preview</th>
|
||||
<th>Filename</th>
|
||||
<th>Size</th>
|
||||
<th>Modified</th>
|
||||
<th>URL</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for file in files %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if file.filename.lower().endswith(('.jpg', '.jpeg', '.png', '.gif', '.webp')) %}
|
||||
<img src="{{ file.url }}" alt="Preview" style="max-width: 50px; max-height: 50px;" class="rounded">
|
||||
{% else %}
|
||||
<i class="fas fa-file" style="font-size: 30px; color: #6c757d;"></i>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ file.filename }}</td>
|
||||
<td>{{ "%.2f"|format(file.size / 1024) }} KB</td>
|
||||
<td>{{ file.modified }}</td>
|
||||
<td>
|
||||
<a href="{{ file.url }}" target="_blank" class="btn btn-sm btn-outline-primary">
|
||||
Buka
|
||||
</a>
|
||||
<button class="btn btn-sm btn-outline-secondary" onclick="copyUrl('{{ file.url }}')">
|
||||
Copy URL
|
||||
</button>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-danger" onclick="deleteFile('{{ file.key }}', this)">
|
||||
Hapus
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-info">
|
||||
<h4>Belum ada file</h4>
|
||||
<p>Belum ada file yang diupload. <a href="/upload">Upload file pertama</a> sekarang!</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<script>
|
||||
function copyUrl(url) {
|
||||
navigator.clipboard.writeText(url).then(function() {
|
||||
alert('URL berhasil dicopy ke clipboard!');
|
||||
});
|
||||
}
|
||||
|
||||
function deleteFile(objectKey, button) {
|
||||
if (confirm('Yakin ingin menghapus file ini?')) {
|
||||
fetch('/api/delete', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
object_key: objectKey
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
// Remove row from table
|
||||
button.closest('tr').remove();
|
||||
alert('File berhasil dihapus!');
|
||||
} else {
|
||||
alert('Error menghapus file: ' + data.error);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
alert('Error: ' + error.message);
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
<!-- templates/index.html -->
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Home - Flask NEO Storage{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-8 mx-auto">
|
||||
<div class="jumbotron bg-light p-5 rounded">
|
||||
<h1 class="display-4">NEO Object Storage Demo</h1>
|
||||
<p class="lead">Demo aplikasi Flask yang terintegrasi dengan BiznetGio NEO Object Storage.</p>
|
||||
<hr class="my-4">
|
||||
<p>Aplikasi ini memungkinkan Anda untuk:</p>
|
||||
<ul>
|
||||
<li>Upload file ke NEO Object Storage</li>
|
||||
<li>Melihat daftar file yang tersimpan</li>
|
||||
<li>Menghapus file dari storage</li>
|
||||
<li>Test koneksi ke NEO</li>
|
||||
</ul>
|
||||
<a class="btn btn-primary btn-lg" href="/upload" role="button">Upload File</a>
|
||||
<a class="btn btn-outline-secondary btn-lg" href="/files" role="button">Lihat Files</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
|
||||
<!-- templates/upload.html -->
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Upload File - Flask NEO Storage{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-6 mx-auto">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4>Upload File ke NEO Object Storage</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<div class="mb-3">
|
||||
<label for="file" class="form-label">Pilih File</label>
|
||||
<input type="file" class="form-control" id="file" name="file" required>
|
||||
<div class="form-text">Semua jenis file diperbolehkan</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Upload File</button>
|
||||
<a href="/files" class="btn btn-outline-secondary">Lihat Files</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Upload via AJAX -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-header">
|
||||
<h5>Upload via AJAX (Advanced)</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="ajaxUploadForm">
|
||||
<div class="mb-3">
|
||||
<label for="ajaxFile" class="form-label">Pilih File</label>
|
||||
<input type="file" class="form-control" id="ajaxFile" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="folder" class="form-label">Folder (opsional)</label>
|
||||
<input type="text" class="form-control" id="folder" placeholder="uploads" value="uploads">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success">Upload dengan AJAX</button>
|
||||
</form>
|
||||
<div id="uploadProgress" class="mt-3" style="display: none;">
|
||||
<div class="progress">
|
||||
<div class="progress-bar" role="progressbar" style="width: 0%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="uploadResult" class="mt-3"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('ajaxUploadForm').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const fileInput = document.getElementById('ajaxFile');
|
||||
const folderInput = document.getElementById('folder');
|
||||
const progressDiv = document.getElementById('uploadProgress');
|
||||
const resultDiv = document.getElementById('uploadResult');
|
||||
|
||||
if (!fileInput.files[0]) {
|
||||
alert('Pilih file terlebih dahulu!');
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', fileInput.files[0]);
|
||||
formData.append('folder', folderInput.value || 'uploads');
|
||||
|
||||
// Show progress
|
||||
progressDiv.style.display = 'block';
|
||||
resultDiv.innerHTML = '';
|
||||
|
||||
fetch('/api/upload', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
progressDiv.style.display = 'none';
|
||||
|
||||
if (data.success) {
|
||||
resultDiv.innerHTML = `
|
||||
<div class="alert alert-success">
|
||||
<h6>Upload berhasil!</h6>
|
||||
<p><strong>URL:</strong> <a href="${data.url}" target="_blank">${data.url}</a></p>
|
||||
<p><strong>Filename:</strong> ${data.filename}</p>
|
||||
</div>
|
||||
`;
|
||||
fileInput.value = '';
|
||||
} else {
|
||||
resultDiv.innerHTML = `
|
||||
<div class="alert alert-danger">
|
||||
<strong>Error:</strong> ${data.error}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
progressDiv.style.display = 'none';
|
||||
resultDiv.innerHTML = `
|
||||
<div class="alert alert-danger">
|
||||
<strong>Error:</strong> ${error.message}
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Loading…
Reference in New Issue