mirror of
https://github.com/JonasunderscoreJones/fileshare.jonasjones.dev.git
synced 2025-10-22 23:19:18 +02:00
Compare commits
3 commits
162863b80a
...
348e07de8f
Author | SHA1 | Date | |
---|---|---|---|
348e07de8f | |||
92489f6b7f | |||
c1c5b81c04 |
1 changed files with 196 additions and 39 deletions
235
src/index.js
235
src/index.js
|
@ -1,7 +1,7 @@
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
|
|
||||||
addEventListener("fetch", event => {
|
addEventListener("fetch", event => {
|
||||||
event.respondWith(handleRequest(event.request));
|
event.respondWith(handleRequest(event));
|
||||||
});
|
});
|
||||||
|
|
||||||
const headersCORS = {
|
const headersCORS = {
|
||||||
|
@ -10,7 +10,36 @@ const headersCORS = {
|
||||||
'Access-Control-Allow-Headers': 'Content-Type, x-Custom-Auth-Key',
|
'Access-Control-Allow-Headers': 'Content-Type, x-Custom-Auth-Key',
|
||||||
};
|
};
|
||||||
|
|
||||||
async function handleRequest(request) {
|
async function recordRequest(request) {
|
||||||
|
|
||||||
|
const analyticsData = {
|
||||||
|
timestamp: Date.now(),
|
||||||
|
domain: new URL(request.url).hostname,
|
||||||
|
method: request.method,
|
||||||
|
path: new URL(request.url).pathname,
|
||||||
|
ipcountry: request.cf.country,
|
||||||
|
}
|
||||||
|
const ANALYTICS_URL = 'https://analytics.jonasjones.dev/requests/record';
|
||||||
|
|
||||||
|
const response = await fetch(ANALYTICS_URL, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': ANALYTICS_API_KEY,
|
||||||
|
},
|
||||||
|
body: JSON.stringify(analyticsData)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
console.log('Request recorded successfully');
|
||||||
|
} else {
|
||||||
|
console.error('Failed to record request:', response.status, await response.text());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleRequest(event) {
|
||||||
|
const request = event.request;
|
||||||
|
event.waitUntil(recordRequest(request));
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
const { pathname } = url;
|
const { pathname } = url;
|
||||||
|
|
||||||
|
@ -28,6 +57,10 @@ async function handleRequest(request) {
|
||||||
return handleUpload(request);
|
return handleUpload(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.method === 'POST' && pathname === '/upload-url') {
|
||||||
|
return handleUrlUpload(request);
|
||||||
|
}
|
||||||
|
|
||||||
if (request.method === 'GET' && pathname.startsWith('/download/')) {
|
if (request.method === 'GET' && pathname.startsWith('/download/')) {
|
||||||
const filename = pathname.replace('/download/', '');
|
const filename = pathname.replace('/download/', '');
|
||||||
return handleDownload(filename);
|
return handleDownload(filename);
|
||||||
|
@ -44,56 +77,106 @@ async function handleRequest(request) {
|
||||||
|
|
||||||
if (request.method === 'GET' && pathname === '/') {
|
if (request.method === 'GET' && pathname === '/') {
|
||||||
return new Response(htmlForm, {
|
return new Response(htmlForm, {
|
||||||
headers: { 'content-type': 'text/html;charset=UTF-8' , ...headersCORS},
|
headers: { 'content-type': 'text/html;charset=UTF-8', ...headersCORS },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Response('Not Found', { status: 404 }, headersCORS);
|
return new Response('Not Found', { status: 404, headers: headersCORS });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleUrlUpload(request) {
|
||||||
|
const { url, authKey, deletionTimestamp } = await request.json();
|
||||||
|
if (!url || !authKey) {
|
||||||
|
return new Response('Bad Request', { status: 400, headers: headersCORS });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authKey !== `Bearer ${AUTH_KEY_SECRET}`) {
|
||||||
|
return new Response('Unauthorized', { status: 401, headers: headersCORS });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const fileResponse = await fetch(url);
|
||||||
|
if (!fileResponse.ok) {
|
||||||
|
return new Response('Failed to download file', { status: 500, headers: headersCORS });
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileBlob = await fileResponse.blob();
|
||||||
|
const hash = nanoid();
|
||||||
|
const contentType = fileResponse.headers.get('Content-Type') || 'application/octet-stream';
|
||||||
|
const originalName = url.split('/').pop();
|
||||||
|
|
||||||
|
// Use provided deletionTimestamp or default to 24 hours from now
|
||||||
|
const expiryTimestamp = deletionTimestamp ? parseInt(deletionTimestamp) : Date.now() + 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
|
await CDN_BUCKET.put(`tempupload/content/${hash}`, fileBlob.stream(), {
|
||||||
|
httpMetadata: { contentType },
|
||||||
|
});
|
||||||
|
|
||||||
|
const indexData = await CDN_BUCKET.get('tempupload/index.json');
|
||||||
|
const index = indexData ? await indexData.json() : [];
|
||||||
|
|
||||||
|
index.push({
|
||||||
|
hash,
|
||||||
|
contentType,
|
||||||
|
originalName,
|
||||||
|
deletionTimestamp: expiryTimestamp,
|
||||||
|
});
|
||||||
|
|
||||||
|
await CDN_BUCKET.put('tempupload/index.json', JSON.stringify(index), {
|
||||||
|
httpMetadata: { contentType: 'application/json' },
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Response(JSON.stringify({ downloadLink: `/download/${hash}` }), {
|
||||||
|
headers: { 'Content-Type': 'application/json', ...headersCORS },
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
return new Response(`Error: ${error.message}`, { status: 500, headers: headersCORS });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function cleanUpExpiredFiles() {
|
async function cleanUpExpiredFiles() {
|
||||||
const indexData = await CDN_BUCKET.get('/tempupload/index.json');
|
const indexData = await CDN_BUCKET.get('tempupload/index.json');
|
||||||
if (!indexData) {
|
if (!indexData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let index = await indexData.json();
|
let index = await indexData.json();
|
||||||
const now = Date.now();
|
|
||||||
const updatedIndex = [];
|
const updatedIndex = [];
|
||||||
|
|
||||||
for (const fileRecord of index) {
|
for (fileRecord of index) {
|
||||||
if (fileRecord.deletionTimestamp <= now) {
|
if (fileRecord.deletionTimestamp <= Date.now()) {
|
||||||
await CDN_BUCKET.delete(`/tempupload/content/${fileRecord.hash}`);
|
await CDN_BUCKET.delete(`tempupload/content/${fileRecord.hash}`);
|
||||||
} else {
|
} else {
|
||||||
updatedIndex.push(fileRecord);
|
updatedIndex.push(fileRecord);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updatedIndex.length !== index.length) {
|
if (updatedIndex.length !== index.length) {
|
||||||
await CDN_BUCKET.put('/tempupload/index.json', JSON.stringify(updatedIndex), {
|
await CDN_BUCKET.put('tempupload/index.json', JSON.stringify(updatedIndex), {
|
||||||
httpMetadata: { contentType: 'application/json' },
|
httpMetadata: { contentType: 'application/json' },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleUpload(request) {
|
async function handleUpload(request) {
|
||||||
|
|
||||||
// Password protection
|
|
||||||
const password = request.headers.get('X-Custom-Auth-Key');
|
const password = request.headers.get('X-Custom-Auth-Key');
|
||||||
if (password !== `Bearer ${AUTH_KEY_SECRET}`) {
|
if (password !== `Bearer ${AUTH_KEY_SECRET}`) {
|
||||||
return new Response('Unauthorized', { status: 401 }, headersCORS);
|
return new Response('Unauthorized', { status: 401, headers: headersCORS });
|
||||||
}
|
}
|
||||||
|
|
||||||
const formData = await request.formData();
|
const formData = await request.formData();
|
||||||
const file = formData.get('file');
|
const file = formData.get('file');
|
||||||
|
const deletionTimestamp = formData.get('deletionTimestamp');
|
||||||
|
console.log('deletionTimestamp:', deletionTimestamp);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return new Response('Bad Request', { status: 400 }, headersCORS);
|
return new Response('Bad Request', { status: 400, headers: headersCORS });
|
||||||
}
|
}
|
||||||
|
|
||||||
const hash = nanoid();
|
const hash = nanoid();
|
||||||
const contentType = file.type;
|
const contentType = file.type;
|
||||||
const originalName = file.name;
|
const originalName = file.name;
|
||||||
const deletionTimestamp = Date.now() + 24 * 60 * 60 * 1000; // 24 hours
|
|
||||||
|
const expiryTimestamp = deletionTimestamp ? parseInt(deletionTimestamp) : Date.now() + 7 * 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
await CDN_BUCKET.put(`tempupload/content/${hash}`, file.stream(), {
|
await CDN_BUCKET.put(`tempupload/content/${hash}`, file.stream(), {
|
||||||
httpMetadata: { contentType },
|
httpMetadata: { contentType },
|
||||||
|
@ -106,7 +189,7 @@ async function handleUpload(request) {
|
||||||
hash,
|
hash,
|
||||||
contentType,
|
contentType,
|
||||||
originalName,
|
originalName,
|
||||||
deletionTimestamp,
|
deletionTimestamp: expiryTimestamp,
|
||||||
});
|
});
|
||||||
|
|
||||||
await CDN_BUCKET.put('tempupload/index.json', JSON.stringify(index), {
|
await CDN_BUCKET.put('tempupload/index.json', JSON.stringify(index), {
|
||||||
|
@ -121,18 +204,18 @@ async function handleUpload(request) {
|
||||||
async function handleDownload(hash) {
|
async function handleDownload(hash) {
|
||||||
const indexData = await CDN_BUCKET.get('tempupload/index.json');
|
const indexData = await CDN_BUCKET.get('tempupload/index.json');
|
||||||
if (!indexData) {
|
if (!indexData) {
|
||||||
return new Response('Not Found', { status: 404 }, headersCORS);
|
return new Response('Not Found', { status: 404, headers: headersCORS });
|
||||||
}
|
}
|
||||||
|
|
||||||
const index = await indexData.json();
|
const index = await indexData.json();
|
||||||
const fileRecord = index.find(file => file.hash === hash);
|
const fileRecord = index.find(file => file.hash === hash);
|
||||||
if (!fileRecord) {
|
if (!fileRecord) {
|
||||||
return new Response('Not Found', { status: 404 }, headersCORS);
|
return new Response('Not Found', { status: 404, headers: headersCORS });
|
||||||
}
|
}
|
||||||
|
|
||||||
const file = await CDN_BUCKET.get(`tempupload/content/${hash}`);
|
const file = await CDN_BUCKET.get(`tempupload/content/${hash}`);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return new Response('Not Found', { status: 404 }, headersCORS);
|
return new Response('Not Found', { status: 404, headers: headersCORS });
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = new Response(file.body, {
|
const response = new Response(file.body, {
|
||||||
|
@ -147,32 +230,23 @@ async function handleDownload(hash) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleDelete(request) {
|
async function handleDelete(request) {
|
||||||
|
|
||||||
// get pathname
|
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
|
|
||||||
const filehash = url.pathname.replace('/delete/', '');
|
const filehash = url.pathname.replace('/delete/', '');
|
||||||
|
|
||||||
console.log('filename', filehash)
|
|
||||||
|
|
||||||
// Password protection
|
|
||||||
const password = request.headers.get('X-Custom-Auth-Key');
|
const password = request.headers.get('X-Custom-Auth-Key');
|
||||||
if (password !== `Bearer ${AUTH_KEY_SECRET}`) {
|
if (password !== `Bearer ${AUTH_KEY_SECRET}`) {
|
||||||
return new Response('Unauthorized', { status: 401 }, headersCORS);
|
return new Response('Unauthorized', { status: 401, headers: headersCORS });
|
||||||
}
|
}
|
||||||
|
|
||||||
const indexData = await CDN_BUCKET.get('tempupload/index.json');
|
const indexData = await CDN_BUCKET.get('tempupload/index.json');
|
||||||
if (await !indexData) {
|
if (await !indexData) {
|
||||||
console.log('indexData', indexData)
|
return new Response('Not Found', { status: 404, headers: headersCORS });
|
||||||
return new Response('Not Found', { status: 404 }, headersCORS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let index = await indexData.json();
|
let index = await indexData.json();
|
||||||
const fileRecord = index.find(file => file.hash === filehash);
|
const fileRecord = index.find(file => file.hash === filehash);
|
||||||
if (!fileRecord) {
|
if (!fileRecord) {
|
||||||
console.log('indexData', indexData)
|
return new Response('Not Found', { status: 404, headers: headersCORS });
|
||||||
console.log('fileRecord', fileRecord)
|
|
||||||
return new Response('Not Found', { status: 404 }, headersCORS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await CDN_BUCKET.delete(`tempupload/content/${fileRecord.hash}`);
|
await CDN_BUCKET.delete(`tempupload/content/${fileRecord.hash}`);
|
||||||
|
@ -182,10 +256,9 @@ async function handleDelete(request) {
|
||||||
httpMetadata: { contentType: 'application/json' },
|
httpMetadata: { contentType: 'application/json' },
|
||||||
});
|
});
|
||||||
|
|
||||||
return new Response('File deleted', { status: 200 }, headersCORS);
|
return new Response('File deleted', { status: 200, headers: headersCORS });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const htmlForm = `
|
const htmlForm = `
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
@ -220,10 +293,24 @@ const htmlForm = `
|
||||||
<form id="uploadForm">
|
<form id="uploadForm">
|
||||||
<input type="file" id="fileInput" name="file" required>
|
<input type="file" id="fileInput" name="file" required>
|
||||||
<input type="password" id="authKey" placeholder="Enter password" required>
|
<input type="password" id="authKey" placeholder="Enter password" required>
|
||||||
|
<label for="deletionDate">Deletion Date (select date or leave blank for 7 days from now):</label>
|
||||||
|
<input type="date" id="deletionDate">
|
||||||
|
<input type="checkbox" id="defaultSevenDays"> Set to delete 7 days from now
|
||||||
<button type="submit">Upload</button>
|
<button type="submit">Upload</button>
|
||||||
</form>
|
</form>
|
||||||
<div id="uploadResponse"></div>
|
<div id="uploadResponse"></div>
|
||||||
|
|
||||||
|
<h1>Upload from URL</h1>
|
||||||
|
<form id="urlUploadForm">
|
||||||
|
<input type="url" id="fileUrl" placeholder="Enter file URL" required>
|
||||||
|
<input type="password" id="urlAuthKey" placeholder="Enter password" required>
|
||||||
|
<label for="urlDeletionDate">Deletion Date (select date or leave blank for 7 days from now):</label>
|
||||||
|
<input type="date" id="urlDeletionDate">
|
||||||
|
<input type="checkbox" id="urlDefaultSevenDays"> Set to delete 7 days from now
|
||||||
|
<button type="submit">Upload</button>
|
||||||
|
</form>
|
||||||
|
<div id="urlUploadResponse"></div>
|
||||||
|
|
||||||
<h1>Delete a File</h1>
|
<h1>Delete a File</h1>
|
||||||
<form id="deleteForm">
|
<form id="deleteForm">
|
||||||
<select id="fileSelect" required>
|
<select id="fileSelect" required>
|
||||||
|
@ -239,7 +326,7 @@ const htmlForm = `
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Original Name</th>
|
<th>Original Name</th>
|
||||||
<th>Deletion Timestamp</th>
|
<th>Deletion Date</th>
|
||||||
<th>Download Link (Hash)</th>
|
<th>Download Link (Hash)</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -247,6 +334,20 @@ const htmlForm = `
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// Calculate 7 days from now in Unix milliseconds
|
||||||
|
function getSevenDaysFromNow() {
|
||||||
|
const now = new Date();
|
||||||
|
return roundToNextDay(now.getTime() + 8 * 24 * 60 * 60 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Round to start of next day
|
||||||
|
function roundToNextDay(timestamp) {
|
||||||
|
const date = new Date(timestamp);
|
||||||
|
date.setHours(24, 0, 0, 0); // Set to 00:00:00 the following day
|
||||||
|
return date.getTime() - 24 * 60 * 60 * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle form submission for file upload
|
||||||
document.getElementById('uploadForm').addEventListener('submit', async (e) => {
|
document.getElementById('uploadForm').addEventListener('submit', async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
@ -255,11 +356,24 @@ const htmlForm = `
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', fileInput.files[0]);
|
formData.append('file', fileInput.files[0]);
|
||||||
|
|
||||||
|
let deletionTimestamp;
|
||||||
|
const deletionDate = document.getElementById('deletionDate').value;
|
||||||
|
const useSevenDays = document.getElementById('defaultSevenDays').checked;
|
||||||
|
|
||||||
|
if (useSevenDays) {
|
||||||
|
deletionTimestamp = getSevenDaysFromNow();
|
||||||
|
} else if (deletionDate) {
|
||||||
|
deletionTimestamp = new Date(deletionDate).getTime();
|
||||||
|
deletionTimestamp = roundToNextDay(deletionTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
formData.append('deletionTimestamp', deletionTimestamp);
|
||||||
|
|
||||||
const responseElement = document.getElementById('uploadResponse');
|
const responseElement = document.getElementById('uploadResponse');
|
||||||
responseElement.textContent = 'Uploading...';
|
responseElement.textContent = 'Uploading...';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch('https://fileshare.jonasjones.dev/upload', {
|
const response = await fetch('/upload', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'X-Custom-Auth-Key': \`Bearer \${authKey}\`
|
'X-Custom-Auth-Key': \`Bearer \${authKey}\`
|
||||||
|
@ -276,6 +390,47 @@ const htmlForm = `
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle form submission for URL upload
|
||||||
|
document.getElementById('urlUploadForm').addEventListener('submit', async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const fileUrl = document.getElementById('fileUrl').value;
|
||||||
|
const authKey = document.getElementById('urlAuthKey').value;
|
||||||
|
|
||||||
|
let deletionTimestamp;
|
||||||
|
const deletionDate = document.getElementById('urlDeletionDate').value;
|
||||||
|
const useSevenDays = document.getElementById('urlDefaultSevenDays').checked;
|
||||||
|
|
||||||
|
if (useSevenDays) {
|
||||||
|
deletionTimestamp = getSevenDaysFromNow();
|
||||||
|
} else if (deletionDate) {
|
||||||
|
deletionTimestamp = new Date(deletionDate).getTime();
|
||||||
|
deletionTimestamp = roundToNextDay(deletionTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
const responseElement = document.getElementById('urlUploadResponse');
|
||||||
|
responseElement.textContent = 'Downloading and uploading...';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('\/upload-url', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'X-Custom-Auth-Key': \`Bearer \${authKey}\`,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ url: fileUrl, authKey: \`Bearer \${authKey}\`, deletionTimestamp })
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
responseElement.textContent = \`Download Link: \${result.downloadLink}\`;
|
||||||
|
fetchFileList();
|
||||||
|
fetchFileTable();
|
||||||
|
} catch (error) {
|
||||||
|
responseElement.textContent = \`Error: \${error.message}\`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle file deletion
|
||||||
document.getElementById('deleteForm').addEventListener('submit', async (e) => {
|
document.getElementById('deleteForm').addEventListener('submit', async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
@ -287,7 +442,7 @@ const htmlForm = `
|
||||||
responseElement.textContent = 'Deleting...';
|
responseElement.textContent = 'Deleting...';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(\`https://fileshare.jonasjones.dev/delete/\${fileHash}\`, {
|
const response = await fetch(\`\/delete/\${fileHash}\`, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
headers: {
|
headers: {
|
||||||
'X-Custom-Auth-Key': \`Bearer \${authKey}\`
|
'X-Custom-Auth-Key': \`Bearer \${authKey}\`
|
||||||
|
@ -303,6 +458,7 @@ const htmlForm = `
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Fetch file list for deletion dropdown
|
||||||
async function fetchFileList() {
|
async function fetchFileList() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('https://cdn.jonasjones.dev/tempupload/index.json');
|
const response = await fetch('https://cdn.jonasjones.dev/tempupload/index.json');
|
||||||
|
@ -311,7 +467,7 @@ const htmlForm = `
|
||||||
fileSelect.innerHTML = '<option value="">Select a file to delete</option>';
|
fileSelect.innerHTML = '<option value="">Select a file to delete</option>';
|
||||||
files.forEach(file => {
|
files.forEach(file => {
|
||||||
const option = document.createElement('option');
|
const option = document.createElement('option');
|
||||||
const deletionDate = new Date(file.deletionTimestamp).toLocaleString();
|
const deletionDate = new Date(file.deletionTimestamp).toLocaleDateString();
|
||||||
option.value = file.hash;
|
option.value = file.hash;
|
||||||
option.textContent = \`\${file.originalName} (deletes on \${deletionDate}) - \${file.hash}\`;
|
option.textContent = \`\${file.originalName} (deletes on \${deletionDate}) - \${file.hash}\`;
|
||||||
fileSelect.appendChild(option);
|
fileSelect.appendChild(option);
|
||||||
|
@ -321,6 +477,7 @@ const htmlForm = `
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch and display file table
|
||||||
async function fetchFileTable() {
|
async function fetchFileTable() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('https://cdn.jonasjones.dev/tempupload/index.json');
|
const response = await fetch('https://cdn.jonasjones.dev/tempupload/index.json');
|
||||||
|
@ -329,11 +486,11 @@ const htmlForm = `
|
||||||
fileTableBody.innerHTML = '';
|
fileTableBody.innerHTML = '';
|
||||||
files.forEach(file => {
|
files.forEach(file => {
|
||||||
const row = document.createElement('tr');
|
const row = document.createElement('tr');
|
||||||
const deletionDate = new Date(file.deletionTimestamp).toLocaleString();
|
const deletionDate = new Date(file.deletionTimestamp).toLocaleDateString();
|
||||||
row.innerHTML = \`
|
row.innerHTML = \`
|
||||||
<td>\${file.originalName}</td>
|
<td>\${file.originalName}</td>
|
||||||
<td>\${deletionDate}</td>
|
<td>\${deletionDate}</td>
|
||||||
<td><a href="https://fileshare.jonasjones.dev/download/\${file.hash}" >\${file.hash}</a></td>
|
<td><a href="\/download/\${file.hash}">\${file.hash}</a></td>
|
||||||
\`;
|
\`;
|
||||||
fileTableBody.appendChild(row);
|
fileTableBody.appendChild(row);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue