god i am done with this program

This commit is contained in:
klein panic
2024-10-02 02:14:57 -04:00
parent dd4b46ecdc
commit cc6f0400b7
19 changed files with 808 additions and 176 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
/venv
assets/*

View File

@@ -2,7 +2,7 @@ from flask import Flask, request, render_template, redirect, url_for, session, s
from flask_talisman import Talisman
from functools import wraps
import os
from security import validate_user
from security import validate_user, is_ip_locked
from data_handler import save_link, save_file, retrieve_uploads, handle_download, get_file_path
from datetime import datetime
from zipfile import ZipFile
@@ -36,11 +36,21 @@ def login_required(f):
@app.before_request
def ensure_login():
if 'username' not in session and request.endpoint not in ('login', 'static'):
ip_address = request.remote_addr
# Check if the IP is locked and redirect to lockout if it is
if is_ip_locked(ip_address) and request.endpoint != 'lockout':
return redirect(url_for('lockout'))
if 'username' not in session and request.endpoint not in ('login', 'static', 'lockout'):
return redirect(url_for('login'))
elif request.endpoint == 'login' and 'username' in session:
session.clear()
@app.route('/lockout')
def lockout():
return render_template("lockout.html")
@app.route('/')
@login_required
def index():
@@ -48,6 +58,12 @@ def index():
@app.route('/login', methods=['GET', 'POST'])
def login():
ip_address = request.remote_addr
# Check if the IP is locked out
if is_ip_locked(ip_address):
return redirect(url_for('lockout'))
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
@@ -77,14 +93,18 @@ def upload_link():
@app.route('/upload/files', methods=['POST'])
@login_required
def upload_files():
if 'files' not in request.files:
# Check if the field name 'files[]' is present in the request
if 'files[]' not in request.files:
return redirect(url_for('index'))
files = request.files.getlist('files')
# Retrieve the list of files with 'files[]'
files = request.files.getlist('files[]')
uploader = session['username']
# Save each file
for file in files:
save_file(uploader, file)
if file: # Check if a file was actually selected
save_file(uploader, file)
return redirect(url_for('index'))

View File

@@ -99,8 +99,14 @@ def reset_login_attempts(username):
def increment_login_attempts(username):
with closing(sqlite3.connect(DATABASE)) as conn, conn, closing(conn.cursor()) as c:
c.execute('UPDATE users SET login_attempts = login_attempts + 1 WHERE username = ?', (username,))
conn.commit()
if username:
c.execute('UPDATE users SET login_attempts = login_attempts + 1 WHERE username = ?', (username,))
c.execute('SELECT login_attempts FROM users WHERE username = ?', (username,))
login_attempts = c.fetchone()[0]
conn.commit()
return login_attempts
else:
return None
def add_upload(uploader, file_type, content):
with closing(sqlite3.connect(DATABASE)) as conn, conn, closing(conn.cursor()) as c:

39
server/security.add.py Normal file
View File

@@ -0,0 +1,39 @@
def validate_user(username, password):
ip_address = request.remote_addr
# Check if the IP is locked
if is_ip_locked(ip_address):
return False, "You have been locked out."
user_data = get_user(username)
if not user_data:
increment_login_attempts(None) # Increment failed attempts for any non-existent username attempt
# Check if IP should be locked
attempts = increment_login_attempts(None)
if attempts >= MAX_ATTEMPTS:
lock_ip(ip_address)
return False, "Maximum login attempts exceeded. You have been locked out."
remaining_attempts = MAX_ATTEMPTS - attempts
return False, f"User does not exist. {remaining_attempts} attempt(s) remaining."
stored_password, salt, login_attempts = user_data
# Check if the maximum login attempts have been reached
if login_attempts >= MAX_ATTEMPTS:
lock_ip(ip_address)
return False, "Maximum login attempts exceeded. You have been locked out."
hashed_password = hash_password(password, salt)
if hashed_password == stored_password:
reset_login_attempts(username)
return True, "Login successful."
else:
increment_login_attempts(username)
if login_attempts + 1 >= MAX_ATTEMPTS:
lock_ip(ip_address)
return False, "Maximum login attempts exceeded. You have been locked out."
remaining_attempts = MAX_ATTEMPTS - login_attempts - 1
return False, f"Invalid credentials. {remaining_attempts} attempt(s) remaining."

View File

@@ -1,9 +1,16 @@
import os # Import for generating random salts
import os
import hashlib
from flask import request
from db_setup import get_user, increment_login_attempts, reset_login_attempts
MAX_ATTEMPTS = 3
LOCKOUT_FILE = "locked_ips.txt"
FAILED_ATTEMPTS = {}
# Ensure the locked_ips.txt file exists
if not os.path.exists(LOCKOUT_FILE):
with open(LOCKOUT_FILE, 'w') as f:
pass
def generate_salt():
"""
@@ -12,39 +19,68 @@ def generate_salt():
return os.urandom(16)
def hash_password(password, salt):
"""
Hashes the password with the provided salt using SHA-256.
"""
# Convert the salt to bytes if it's a string
if isinstance(salt, str):
salt = salt.encode()
return hashlib.sha256(salt + password.encode()).hexdigest()
def is_ip_locked(ip):
"""
Checks if the IP address is in the lockout list.
"""
if os.path.exists(LOCKOUT_FILE):
with open(LOCKOUT_FILE, 'r') as f:
locked_ips = f.read().splitlines()
return ip in locked_ips
return False
def lock_ip(ip):
"""
Adds an IP address to the lockout list.
"""
with open(LOCKOUT_FILE, 'a') as f:
f.write(ip + "\n")
def validate_user(username, password):
"""
Validates the user's credentials against stored data.
"""
ip_address = request.remote_addr
# Check if the IP is locked
if is_ip_locked(ip_address):
return False, "You have been locked out."
# Check or increment failed attempts for this IP address
if ip_address not in FAILED_ATTEMPTS:
FAILED_ATTEMPTS[ip_address] = 0
user_data = get_user(username)
if not user_data:
print(f"User '{username}' does not exist.")
return False, "User does not exist."
FAILED_ATTEMPTS[ip_address] += 1
if FAILED_ATTEMPTS[ip_address] >= MAX_ATTEMPTS:
lock_ip(ip_address)
return False, "Maximum login attempts exceeded. You have been locked out."
remaining_attempts = MAX_ATTEMPTS - FAILED_ATTEMPTS[ip_address]
return False, f"User does not exist. {remaining_attempts} attempt(s) remaining."
stored_password, salt, login_attempts = user_data
# Check if the maximum login attempts have been reached
if login_attempts >= MAX_ATTEMPTS:
print(f"User '{username}' has exceeded max login attempts.")
return False, "Maximum login attempts exceeded. Please contact the administrator."
# Hash the provided password with the salt
hashed_password = hash_password(password, salt)
print(f"Provided hash: {hashed_password}, Stored hash: {stored_password}")
if hashed_password == stored_password:
reset_login_attempts(username)
print(f"User '{username}' logged in successfully.")
# Clear failed attempts for this IP on a successful login
FAILED_ATTEMPTS.pop(ip_address, None)
return True, "Login successful."
else:
increment_login_attempts(username)
remaining_attempts = MAX_ATTEMPTS - login_attempts - 1
print(f"Invalid credentials for '{username}'. {remaining_attempts} attempt(s) remaining.")
FAILED_ATTEMPTS[ip_address] += 1
if FAILED_ATTEMPTS[ip_address] >= MAX_ATTEMPTS:
lock_ip(ip_address)
return False, "Maximum login attempts exceeded. You have been locked out."
remaining_attempts = MAX_ATTEMPTS - FAILED_ATTEMPTS[ip_address]
return False, f"Invalid credentials. {remaining_attempts} attempt(s) remaining."
def identify_uploader():

79
server/security.py.bak Normal file
View File

@@ -0,0 +1,79 @@
import os # Import for generating random salts
import hashlib
from flask import request
from db_setup import get_user, increment_login_attempts, reset_login_attempts
MAX_ATTEMPTS = 3
def generate_salt():
"""
Generates a 16-byte random salt.
"""
return os.urandom(16)
def hash_password(password, salt):
# Convert the salt to bytes if it's a string
if isinstance(salt, str):
salt = salt.encode()
return hashlib.sha256(salt + password.encode()).hexdigest()
def validate_user(username, password):
"""
Validates the user's credentials against stored data.
"""
user_data = get_user(username)
if not user_data:
print(f"User '{username}' does not exist.")
return False, "User does not exist."
stored_password, salt, login_attempts = user_data
# Check if the maximum login attempts have been reached
if login_attempts >= MAX_ATTEMPTS:
print(f"User '{username}' has exceeded max login attempts.")
return False, "Maximum login attempts exceeded. Please contact the administrator."
# Hash the provided password with the salt
hashed_password = hash_password(password, salt)
print(f"Provided hash: {hashed_password}, Stored hash: {stored_password}")
if hashed_password == stored_password:
reset_login_attempts(username)
print(f"User '{username}' logged in successfully.")
return True, "Login successful."
else:
increment_login_attempts(username)
remaining_attempts = MAX_ATTEMPTS - login_attempts - 1
print(f"Invalid credentials for '{username}'. {remaining_attempts} attempt(s) remaining.")
return False, f"Invalid credentials. {remaining_attempts} attempt(s) remaining."
def identify_uploader():
"""
Identifies the uploader's device information from the request headers.
"""
device_info = get_device_info()
user_agent = device_info['user_agent']
if "iPhone" in user_agent:
device_type = "iPhone"
elif "Android" in user_agent:
device_type = "Android"
elif "Windows" in user_agent:
device_type = "Windows PC"
elif "Mac" in user_agent:
device_type = "Mac"
elif "Linux" in user_agent:
device_type = "Linux Machine"
else:
device_type = "Unknown Device"
return f"Uploaded by {device_type} (IP: {device_info['ip']})"
def get_device_info():
"""
Extracts device information from the request.
"""
return {
"ip": request.remote_addr or "Unknown IP",
"user_agent": request.headers.get('User-Agent', 'Unknown'),
}

47
static/error.css Normal file
View File

@@ -0,0 +1,47 @@
/* error.css */
body {
font-family: Arial, sans-serif;
background-color: #f8d7da;
color: #721c24;
margin: 0;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
.error-container {
background-color: #f5c6cb;
padding: 20px 40px;
border: 1px solid #f1b0b7;
border-radius: 8px;
text-align: center;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
h1 {
font-size: 2em;
margin: 0 0 10px 0;
}
p {
font-size: 1.2em;
margin: 10px 0;
}
a {
color: #721c24;
text-decoration: none;
font-weight: bold;
background-color: #f1b0b7;
padding: 8px 15px;
border-radius: 5px;
display: inline-block;
margin-top: 10px;
}
a:hover {
background-color: #f8d7da;
}

BIN
static/eye.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 KiB

85
static/index.css Normal file
View File

@@ -0,0 +1,85 @@
/* static/index.css */
body {
background-color: #f0f4f8;
font-family: Arial, sans-serif;
color: #333;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
text-align: center;
}
.container {
background-color: #ffffff;
padding: 30px 40px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
max-width: 500px;
width: 100%;
}
h1 {
color: #007acc;
margin-bottom: 20px;
}
h2 {
color: #333;
margin: 15px 0;
font-size: 1.2em;
}
form {
margin: 15px 0;
}
input[type="text"], input[type="file"] {
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
width: 100%;
box-sizing: border-box;
margin-bottom: 10px;
}
button {
background-color: #007acc;
color: #fff;
border: none;
padding: 10px 15px;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s ease;
}
button:hover {
background-color: #005f99;
}
button:active {
background-color: #004e7a;
}
button:focus {
outline: none;
box-shadow: 0 0 5px #007acc;
}
#linkForm, #fileForm {
display: flex;
flex-direction: column;
align-items: center;
}
#linkForm input[type="text"], #fileForm input[type="file"] {
width: 80%;
margin-bottom: 10px;
}
.view-btn {
margin-top: 20px;
display: inline-block;
}

55
static/lockout.css Normal file
View File

@@ -0,0 +1,55 @@
/* static/lockout.css */
body {
background-color: #f8d7da;
font-family: Arial, sans-serif;
color: #721c24;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
text-align: center;
}
.container {
background-color: #ffffff;
padding: 30px 40px;
border: 2px solid #f5c6cb;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
max-width: 600px;
width: 100%;
}
h1 {
color: #721c24;
margin-bottom: 20px;
}
p {
color: #856404;
background-color: #fff3cd;
border: 1px solid #ffeeba;
padding: 10px;
border-radius: 4px;
}
.contact {
margin-top: 20px;
color: #004085;
background-color: #cce5ff;
border: 1px solid #b8daff;
padding: 10px;
border-radius: 4px;
}
.contact a {
color: #004085;
text-decoration: none;
font-weight: bold;
}
.contact a:hover {
text-decoration: underline;
}

View File

@@ -1,6 +1,10 @@
/* Centering the login container */
body {
background-color: #f0f0f0; /* Light grey background for the whole page */
background-image: url('/static/eye.jpeg');
background-size: cover; /* Ensures the image covers the entire background */
background-position: center; /* Centers the image */
background-repeat: no-repeat; /* Prevents the background from repeating */
background-color: #f0f0f0; /* Fallback color if the image doesn't load */
display: flex;
justify-content: center;
align-items: center;

102
static/uploads.css Normal file
View File

@@ -0,0 +1,102 @@
/* static/uploads.css */
body {
background-color: #f0f4f8;
font-family: Arial, sans-serif;
color: #333;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100%;
text-align: center;
}
.container {
background-color: #ffffff;
padding: 30px 40px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
max-width: 700px;
width: 100%;
}
h1 {
color: #007acc;
margin-bottom: 20px;
}
h2 {
color: #333;
margin: 15px 0;
font-size: 1.2em;
border-bottom: 2px solid #007acc;
display: inline-block;
padding-bottom: 5px;
}
ul {
list-style-type: none;
padding: 0;
}
li {
padding: 10px;
margin: 5px 0;
border: 1px solid #ddd;
border-radius: 4px;
background-color: #f9f9f9;
display: flex;
justify-content: space-between;
align-items: center;
}
li:nth-child(odd) {
background-color: #eef3f7;
}
button {
background-color: #007acc;
color: #fff;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s ease;
margin-left: 5px;
}
button:hover {
background-color: #005f99;
}
button:focus {
outline: none;
box-shadow: 0 0 5px #007acc;
}
a {
color: #007acc;
text-decoration: none;
transition: color 0.3s ease;
}
a:hover {
color: #005f99;
}
.back-link {
display: inline-block;
margin-top: 20px;
background-color: #007acc;
color: #fff;
padding: 10px 20px;
text-decoration: none;
border-radius: 4px;
transition: background-color 0.3s ease;
}
.back-link:hover {
background-color: #005f99;
}

View File

@@ -4,10 +4,13 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Error</title>
<link rel="stylesheet" href="{{ url_for('static', filename='error.css') }}">
</head>
<body>
<h1>An error occurred</h1>
<p>{{ error_message }}</p>
<a href="/">Go back to the main page</a>
<div class="error-container">
<h1>An error occurred</h1>
<p>{{ error_message }}</p>
<a href="/">Go back to the main page</a>
</div>
</body>
</html>

View File

@@ -5,26 +5,29 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>iPhone-Linux Transfer</title>
<link rel="stylesheet" href="{{ url_for('static', filename='index.css') }}">
</head>
<body>
<h1>iPhone-Linux Transfer Service</h1>
<div class="container">
<h1>iPhone-Linux Transfer Service</h1>
<!-- Upload HTML link form -->
<h2>Upload HTML Link</h2>
<form id="linkForm" action="/upload/link" method="POST">
<input type="text" name="link" placeholder="Enter your link here" required>
<button type="submit">Submit Link</button>
</form>
<!-- Upload HTML link form -->
<h2>Upload HTML Link</h2>
<form id="linkForm" action="/upload/link" method="POST">
<input type="text" name="link" placeholder="Enter your link here" required>
<button type="submit">Submit Link</button>
</form>
<!-- Upload file form -->
<h2>Upload Image/File</h2>
<form id="fileForm" action="/upload/file" method="POST" enctype="multipart/form-data">
<input type="file" name="file" required>
<button type="submit">Upload File</button>
</form>
<!-- Upload file form -->
<h2>Upload Image/File</h2>
<form id="fileForm" action="/upload/files" method="POST" enctype="multipart/form-data">
<input type="file" name="files[]" multiple required>
<button type="submit">Upload File</button>
</form>
<!-- Button to view uploaded content -->
<h2>View Uploaded Links and Images</h2>
<button onclick="window.location.href='/uploads';">View Uploaded Content</button>
<!-- Button to view uploaded content -->
<h2>View Uploaded Links and Images</h2>
<button class="view-btn" onclick="window.location.href='/uploads';">View Uploaded Content</button>
</div>
</body>
</html>

View File

@@ -1,11 +1,20 @@
<!-- templates/lockout.html -->
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Account Locked Out</title>
<link rel="stylesheet" href="{{ url_for('static', filename='lockout.css') }}">
</head>
<body>
<h1>You have been locked out due to too many failed login attempts.</h1>
<p>If you believe this is an error, please contact the administrator.</p>
<div class="container">
<h1>Account Locked Out</h1>
<p>You have been locked out due to too many failed login attempts.</p>
<div class="contact">
<p>If you believe this is an error, please contact the administrator.</p>
</div>
</div>
</body>
</html>

View File

@@ -1,11 +1,12 @@
<!-- templates/uploads.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Uploaded Data</title>
<link rel="stylesheet" href="{{ url_for('static', filename='uploads.css') }}">
<script>
// Function to download an item
function downloadItem(url) {
fetch(url)
.then(response => {
@@ -27,81 +28,141 @@
});
}
// Function to confirm deletion
function confirmDelete(url) {
if (confirm("Are you sure you want to delete this item?")) {
window.location.href = url;
}
}
// Function to rename a file
function renameItem(uploadId) {
const newName = prompt("Enter new name for the file:");
if (newName) {
fetch(`/rename/${uploadId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ new_name: newName }),
})
.then(response => {
if (!response.ok) throw new Error('Failed to rename');
alert('File renamed successfully');
location.reload(); // Reload the page to show updated names
})
.catch(error => {
alert('Error renaming file:', error);
});
}
}
// Function to preview a file
function previewItem(uploadId) {
window.open(`/preview/${uploadId}`, '_blank');
}
// Function to download all files of a certain type
function downloadAll(url) {
window.location.href = url;
}
</script>
</head>
<body>
<h1>Uploaded Data</h1>
<div class="container">
<h1>Uploaded Data</h1>
<!-- Links Section -->
<h2>Links</h2>
{% if links %}
<ul>
{% for link in links %}
<li>
<a href="{{ link[3] }}" target="_blank">{{ link[3] }}</a>
(Uploaded by: {{ link[1] }})
<button onclick="downloadItem('/download_link/{{ link[0] }}');">Download</button>
<button onclick="confirmDelete('/delete_link/{{ link[0] }}');">Delete</button>
</li>
{% endfor %}
</ul>
{% else %}
<p>No links uploaded.</p>
{% endif %}
<!-- Links Section -->
<h2>Links</h2>
{% if links %}
<ul>
{% for link in links %}
<li>
<span>
<a href="{{ link[3] }}" target="_blank">{{ link[3] }}</a>
(Uploaded by: {{ link[1] }})
</span>
<div>
<button onclick="downloadItem('/download_link/{{ link[0] }}');">Download</button>
<button onclick="confirmDelete('/delete_link/{{ link[0] }}');">Delete</button>
</div>
</li>
{% endfor %}
</ul>
<button onclick="downloadAll('/download_all_links');">Download All Links</button>
{% else %}
<p>No links uploaded.</p>
{% endif %}
<!-- Videos Section -->
<h2>Videos</h2>
{% if videos %}
<ul>
{% for video in videos %}
<li>
{{ video[3] }} (Uploaded by: {{ video[1] }})
<button onclick="downloadItem('/download/{{ video[0] }}');">Download</button>
<button onclick="confirmDelete('/delete_file/{{ video[0] }}');">Delete</button>
</li>
{% endfor %}
</ul>
{% else %}
<p>No videos uploaded.</p>
{% endif %}
<!-- Videos Section -->
<h2>Videos</h2>
{% if videos %}
<ul>
{% for video in videos %}
<li>
<span>
{{ video[3] }} (Uploaded by: {{ video[1] }})
</span>
<div>
<button onclick="previewItem({{ video[0] }});">Preview</button>
<button onclick="renameItem({{ video[0] }});">Rename</button>
<button onclick="downloadItem('/download/{{ video[0] }}');">Download</button>
<button onclick="confirmDelete('/delete_file/{{ video[0] }}');">Delete</button>
</div>
</li>
{% endfor %}
</ul>
<button onclick="downloadAll('/download_all_videos');">Download All Videos</button>
{% else %}
<p>No videos uploaded.</p>
{% endif %}
<!-- Photos Section -->
<h2>Photos</h2>
{% if photos %}
<ul>
{% for photo in photos %}
<li>
{{ photo[3] }} (Uploaded by: {{ photo[1] }})
<button onclick="downloadItem('/download/{{ photo[0] }}');">Download</button>
<button onclick="confirmDelete('/delete_file/{{ photo[0] }}');">Delete</button>
</li>
{% endfor %}
</ul>
{% else %}
<p>No photos uploaded.</p>
{% endif %}
<!-- Photos Section -->
<h2>Photos</h2>
{% if photos %}
<ul>
{% for photo in photos %}
<li>
<span>
{{ photo[3] }} (Uploaded by: {{ photo[1] }})
</span>
<div>
<button onclick="previewItem({{ photo[0] }});">Preview</button>
<button onclick="renameItem({{ photo[0] }});">Rename</button>
<button onclick="downloadItem('/download/{{ photo[0] }}');">Download</button>
<button onclick="confirmDelete('/delete_file/{{ photo[0] }}');">Delete</button>
</div>
</li>
{% endfor %}
</ul>
{% else %}
<p>No photos uploaded.</p>
{% endif %}
<!-- Miscellaneous Files Section -->
<h2>Miscellaneous Files</h2>
{% if misc %}
<ul>
{% for item in misc %}
<li>
{{ item[3] }} (Uploaded by: {{ item[1] }})
<button onclick="downloadItem('/download/{{ item[0] }}');">Download</button>
<button onclick="confirmDelete('/delete_file/{{ item[0] }}');">Delete</button>
</li>
{% endfor %}
</ul>
{% else %}
<p>No miscellaneous files uploaded.</p>
{% endif %}
<!-- Miscellaneous Files Section -->
<h2>Miscellaneous Files</h2>
{% if misc %}
<ul>
{% for item in misc %}
<li>
<span>
{{ item[3] }} (Uploaded by: {{ item[1] }})
</span>
<div>
<button onclick="previewItem({{ item[0] }});">Preview</button>
<button onclick="renameItem({{ item[0] }});">Rename</button>
<button onclick="downloadItem('/download/{{ item[0] }}');">Download</button>
<button onclick="confirmDelete('/delete_file/{{ item[0] }}');">Delete</button>
</div>
</li>
{% endfor %}
</ul>
<button onclick="downloadAll('/download_all_misc');">Download All Misc Files</button>
{% else %}
<p>No miscellaneous files uploaded.</p>
{% endif %}
<a href="/">Back to Upload Page</a>
<a class="back-link" href="/">Back to Upload Page</a>
</div>
</body>
</html>

View File

@@ -1,78 +1,160 @@
<!-- templates/uploads.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Uploaded Data</title>
<link rel="stylesheet" href="{{ url_for('static', filename='uploads.css') }}">
<script>
// Function to download an item
function downloadItem(url) {
fetch(url)
.then(response => {
if (!response.ok) throw new Error('Network response was not ok');
return response.blob();
})
.then(blob => {
const downloadUrl = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = downloadUrl;
a.download = url.split('/').pop(); // This sets the downloaded file name
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(downloadUrl); // Clean up URL object
})
.catch(error => {
console.error('Download failed:', error);
});
}
// Function to confirm deletion
function confirmDelete(url) {
if (confirm("Are you sure you want to delete this item?")) {
window.location.href = url;
}
}
// Function to rename a file
function renameItem(uploadId) {
const newName = prompt("Enter new name for the file:");
if (newName) {
fetch(`/rename/${uploadId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ new_name: newName }),
})
.then(response => {
if (!response.ok) throw new Error('Failed to rename');
alert('File renamed successfully');
location.reload(); // Reload the page to show updated names
})
.catch(error => {
alert('Error renaming file:', error);
});
}
}
// Function to preview a file
function previewItem(uploadId) {
window.open(`/preview/${uploadId}`, '_blank');
}
</script>
</head>
<body>
<h1>Uploaded Data</h1>
<div class="container">
<h1>Uploaded Data</h1>
<!-- Links Section -->
<h2>Links</h2>
{% if links %}
{% if links|length > 1 %}
<button onclick="window.location.href='/download_all_links';">Download All Links</button>
<!-- Links Section -->
<h2>Links</h2>
{% if links %}
<ul>
{% for link in links %}
<li>
<span>
<a href="{{ link[3] }}" target="_blank">{{ link[3] }}</a>
(Uploaded by: {{ link[1] }})
</span>
<div>
<button onclick="downloadItem('/download_link/{{ link[0] }}');">Download</button>
<button onclick="confirmDelete('/delete_link/{{ link[0] }}');">Delete</button>
</div>
</li>
{% endfor %}
</ul>
{% else %}
<p>No links uploaded.</p>
{% endif %}
<ul>
{% for link in links %}
<li>
<a href="{{ link[3] }}" target="_blank">{{ link[3] }}</a>
(Uploaded by: {{ link[1] }})
<button onclick="window.location.href='/download_link/{{ link[0] }}';">Download</button>
</li>
{% endfor %}
</ul>
{% else %}
<p>No links uploaded.</p>
{% endif %}
<!-- Videos Section -->
<h2>Videos</h2>
{% if videos %}
<ul>
{% for video in videos %}
<li>
{{ video[3] }} (Uploaded by: {{ video[1] }})
<button onclick="window.location.href='/download/{{ video[0] }}';">Download</button>
</li>
{% endfor %}
</ul>
{% else %}
<p>No videos uploaded.</p>
{% endif %}
<!-- Videos Section -->
<h2>Videos</h2>
{% if videos %}
<ul>
{% for video in videos %}
<li>
<span>
{{ video[3] }} (Uploaded by: {{ video[1] }})
</span>
<div>
<button onclick="previewItem({{ video[0] }});">Preview</button>
<button onclick="renameItem({{ video[0] }});">Rename</button>
<button onclick="downloadItem('/download/{{ video[0] }}');">Download</button>
<button onclick="confirmDelete('/delete_file/{{ video[0] }}');">Delete</button>
</div>
</li>
{% endfor %}
</ul>
{% else %}
<p>No videos uploaded.</p>
{% endif %}
<!-- Photos Section -->
<h2>Photos</h2>
{% if photos %}
<ul>
{% for photo in photos %}
<li>
{{ photo[3] }} (Uploaded by: {{ photo[1] }})
<button onclick="window.location.href='/download/{{ photo[0] }}';">Download</button>
</li>
{% endfor %}
</ul>
{% else %}
<p>No photos uploaded.</p>
{% endif %}
<!-- Photos Section -->
<h2>Photos</h2>
{% if photos %}
<ul>
{% for photo in photos %}
<li>
<span>
{{ photo[3] }} (Uploaded by: {{ photo[1] }})
</span>
<div>
<button onclick="previewItem({{ photo[0] }});">Preview</button>
<button onclick="renameItem({{ photo[0] }});">Rename</button>
<button onclick="downloadItem('/download/{{ photo[0] }}');">Download</button>
<button onclick="confirmDelete('/delete_file/{{ photo[0] }}');">Delete</button>
</div>
</li>
{% endfor %}
</ul>
{% else %}
<p>No photos uploaded.</p>
{% endif %}
<!-- Miscellaneous Files Section -->
<h2>Miscellaneous Files</h2>
{% if misc %}
<ul>
{% for item in misc %}
<li>
{{ item[3] }} (Uploaded by: {{ item[1] }})
<button onclick="window.location.href='/download/{{ item[0] }}';">Download</button>
</li>
{% endfor %}
</ul>
{% else %}
<p>No miscellaneous files uploaded.</p>
{% endif %}
<!-- Miscellaneous Files Section -->
<h2>Miscellaneous Files</h2>
{% if misc %}
<ul>
{% for item in misc %}
<li>
<span>
{{ item[3] }} (Uploaded by: {{ item[1] }})
</span>
<div>
<button onclick="previewItem({{ item[0] }});">Preview</button>
<button onclick="renameItem({{ item[0] }});">Rename</button>
<button onclick="downloadItem('/download/{{ item[0] }}');">Download</button>
<button onclick="confirmDelete('/delete_file/{{ item[0] }});">Delete</button>
</div>
</li>
{% endfor %}
</ul>
{% else %}
<p>No miscellaneous files uploaded.</p>
{% endif %}
<a href="/">Back to Upload Page</a>
<a class="back-link" href="/">Back to Upload Page</a>
</div>
</body>
</html>