forked from spitkov/sxbin
too many changes for me to list but basically user suppport file lsiting uploading deleting renaming moving copying etc and toggle if index.html presnet shw it to acces ur page /username and then ASKDJAKLSDl this is a development why do i have to document everything
This commit is contained in:
parent
7c641df41e
commit
0f444b7606
446
app.py
446
app.py
@ -1,20 +1,19 @@
|
||||
from flask import Flask, request, jsonify, send_from_directory, render_template, url_for, redirect, send_file
|
||||
from flask import Flask, request, jsonify, send_from_directory, render_template, url_for, redirect, send_file, session
|
||||
from werkzeug.utils import secure_filename
|
||||
import shortuuid
|
||||
import os
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
import zipfile
|
||||
import sqlite3
|
||||
import threading
|
||||
import time
|
||||
import shutil
|
||||
from datetime import timedelta
|
||||
from pygments import highlight
|
||||
from pygments.lexers import get_lexer_by_name, guess_lexer
|
||||
from pygments.formatters import HtmlFormatter
|
||||
from pygments.util import ClassNotFound
|
||||
import json
|
||||
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
|
||||
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user, login_remembered
|
||||
import hashlib
|
||||
|
||||
app = Flask(__name__)
|
||||
@ -22,6 +21,7 @@ app.secret_key = 'your_secret_key_here' # Add this line
|
||||
UPLOAD_FOLDER = './uploads'
|
||||
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
|
||||
DATABASE = 'data.db'
|
||||
app.config['REMEMBER_COOKIE_DURATION'] = timedelta(days=30) # Set cookie to expire after 30 days
|
||||
|
||||
if not os.path.exists(UPLOAD_FOLDER):
|
||||
os.makedirs(UPLOAD_FOLDER)
|
||||
@ -115,146 +115,82 @@ def load_user(user_id):
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return render_template('index.html')
|
||||
if current_user.is_authenticated:
|
||||
return render_template('index.html', user=current_user)
|
||||
return render_template('index.html', user=None)
|
||||
|
||||
@app.route('/content/<vanity>')
|
||||
def content(vanity):
|
||||
@app.route('/u/<username>')
|
||||
@app.route('/u/<username>/')
|
||||
@app.route('/u/<username>/<path:filename>')
|
||||
def serve_user_page(username, filename=None):
|
||||
print(f"Accessing user page: {username}, filename: {filename}") # Debug print
|
||||
|
||||
# Check if the username exists in the database
|
||||
db = get_db()
|
||||
cursor = db.cursor()
|
||||
cursor.execute("SELECT * FROM content WHERE vanity = ?", (vanity,))
|
||||
target = cursor.fetchone()
|
||||
cursor.execute("SELECT * FROM users WHERE username = ?", (username,))
|
||||
user = cursor.fetchone()
|
||||
if not user:
|
||||
print(f"User {username} not found") # Debug print
|
||||
return "User not found", 404
|
||||
|
||||
user_folder = os.path.join(app.config['UPLOAD_FOLDER'], username)
|
||||
print(f"User folder path: {user_folder}") # Debug print
|
||||
|
||||
if target:
|
||||
content_type, content_data = target[1], target[2]
|
||||
if content_type == 'pastebin':
|
||||
try:
|
||||
lexer = guess_lexer(content_data)
|
||||
language = lexer.aliases[0]
|
||||
except ClassNotFound:
|
||||
language = 'text'
|
||||
lexer = get_lexer_by_name(language)
|
||||
|
||||
formatter = HtmlFormatter(style='monokai', linenos=True, cssclass="source")
|
||||
highlighted_code = highlight(content_data, lexer, formatter)
|
||||
css = formatter.get_style_defs('.source')
|
||||
return render_template('content.html',
|
||||
highlighted_content=highlighted_code,
|
||||
css=css,
|
||||
raw_content=content_data,
|
||||
created_at=target[3],
|
||||
vanity=vanity,
|
||||
language=language)
|
||||
elif content_type == 'file':
|
||||
file_path = os.path.join(app.config['UPLOAD_FOLDER'], f'{vanity}_{content_data}')
|
||||
file_info = {
|
||||
'name': content_data,
|
||||
'size': os.path.getsize(file_path),
|
||||
'modified_at': datetime.fromtimestamp(os.path.getmtime(file_path)).strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'url': url_for('download_file', vanity=vanity)
|
||||
}
|
||||
return render_template('file.html', **file_info)
|
||||
elif content_type == 'url':
|
||||
return render_template('content.html', url=content_data)
|
||||
return 'Not Found', 404
|
||||
if not os.path.exists(user_folder):
|
||||
print(f"User folder does not exist for {username}") # Debug print
|
||||
os.makedirs(user_folder) # Create the folder if it doesn't exist
|
||||
|
||||
@app.route('/download/<vanity>', methods=['GET'])
|
||||
def download_file(vanity):
|
||||
db = get_db()
|
||||
cursor = db.cursor()
|
||||
cursor.execute("SELECT * FROM content WHERE vanity = ? AND type = 'file'", (vanity,))
|
||||
target = cursor.fetchone()
|
||||
if target:
|
||||
filename = f'{vanity}_{target[2]}'
|
||||
return send_from_directory(app.config['UPLOAD_FOLDER'], filename, as_attachment=True)
|
||||
return 'Not Found', 404
|
||||
current_path = os.path.join(user_folder, filename.rstrip('/') if filename else '')
|
||||
if not os.path.exists(current_path):
|
||||
return "Folder or file not found", 404
|
||||
|
||||
@app.route('/upload/pastebin', methods=['POST'])
|
||||
def upload_pastebin():
|
||||
content = request.form['content']
|
||||
vanity = shortuuid.uuid()[:6]
|
||||
created_at = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
db = get_db()
|
||||
cursor = db.cursor()
|
||||
cursor.execute("INSERT INTO content (vanity, type, data, created_at) VALUES (?, ?, ?, ?)",
|
||||
(vanity, 'pastebin', content, created_at))
|
||||
db.commit()
|
||||
|
||||
return jsonify({'vanity': vanity})
|
||||
if os.path.isfile(current_path):
|
||||
return send_file(current_path)
|
||||
|
||||
@app.route('/upload/file', methods=['POST'])
|
||||
def upload_file():
|
||||
if 'file' not in request.files:
|
||||
return 'No file part', 400
|
||||
file = request.files['file']
|
||||
if file.filename == '':
|
||||
return 'No selected file', 400
|
||||
if file:
|
||||
vanity = shortuuid.uuid()[:6]
|
||||
filename = secure_filename(file.filename)
|
||||
filepath = os.path.join(app.config['UPLOAD_FOLDER'], f'{vanity}_{filename}')
|
||||
file.save(filepath)
|
||||
|
||||
db = get_db()
|
||||
cursor = db.cursor()
|
||||
cursor.execute("INSERT INTO content (vanity, type, data) VALUES (?, ?, ?)",
|
||||
(vanity, 'file', filename))
|
||||
db.commit()
|
||||
|
||||
return jsonify({'vanity': vanity})
|
||||
# Check if we should ignore index.html
|
||||
ignore_index = session.get(f'ignore_index_{username}', False)
|
||||
|
||||
def save_file(file, folder_path):
|
||||
filename = secure_filename(file.filename)
|
||||
file_path = os.path.join(folder_path, filename)
|
||||
file.save(file_path)
|
||||
# Check for index.html
|
||||
index_path = os.path.join(current_path, 'index.html')
|
||||
if os.path.exists(index_path) and not ignore_index:
|
||||
return send_file(index_path)
|
||||
|
||||
def handle_uploaded_folder(files, base_path):
|
||||
for file in files:
|
||||
if file.filename.endswith('/'):
|
||||
subfolder_path = os.path.join(base_path, secure_filename(file.filename))
|
||||
os.makedirs(subfolder_path, exist_ok=True)
|
||||
handle_uploaded_folder(request.files.getlist(file.filename), subfolder_path)
|
||||
# Directory listing
|
||||
files = []
|
||||
folders = []
|
||||
for item in os.listdir(current_path):
|
||||
item_path = os.path.join(current_path, item)
|
||||
relative_path = os.path.relpath(item_path, user_folder)
|
||||
if os.path.isfile(item_path):
|
||||
files.append({'name': item, 'path': relative_path})
|
||||
else:
|
||||
save_file(file, base_path)
|
||||
folders.append({'name': item, 'path': relative_path})
|
||||
|
||||
@app.route('/upload/folder', methods=['POST'])
|
||||
def upload_folder():
|
||||
if 'file' not in request.files:
|
||||
return 'No files uploaded', 400
|
||||
|
||||
files = request.files.getlist('file')
|
||||
if not files:
|
||||
return 'No files selected', 400
|
||||
|
||||
vanity = shortuuid.uuid()[:6]
|
||||
folder_path = os.path.join(app.config['UPLOAD_FOLDER'], vanity)
|
||||
os.makedirs(folder_path)
|
||||
parent_folder = os.path.dirname(filename.rstrip('/')) if filename else None
|
||||
current_folder = os.path.basename(current_path)
|
||||
|
||||
handle_uploaded_folder(files, folder_path)
|
||||
|
||||
db = get_db()
|
||||
cursor = db.cursor()
|
||||
cursor.execute("INSERT INTO content (vanity, type, data) VALUES (?, ?, ?)",
|
||||
(vanity, 'folder', ','.join([file.filename for file in files])))
|
||||
db.commit()
|
||||
# Generate the correct parent folder URL
|
||||
parent_url = None
|
||||
if parent_folder:
|
||||
parent_url = url_for('serve_user_page', username=username, filename=parent_folder)
|
||||
elif filename: # If we're in a subfolder, parent is the root
|
||||
parent_url = url_for('serve_user_page', username=username)
|
||||
|
||||
return jsonify({'vanity': vanity})
|
||||
return render_template('user_files_public.html',
|
||||
username=username,
|
||||
files=files,
|
||||
folders=folders,
|
||||
current_path=filename.rstrip('/') if filename else '',
|
||||
parent_url=parent_url,
|
||||
current_folder=current_folder)
|
||||
|
||||
@app.route('/shorten', methods=['POST'])
|
||||
def shorten_url():
|
||||
original_url = request.form['url']
|
||||
vanity = shortuuid.uuid()[:6]
|
||||
|
||||
db = get_db()
|
||||
cursor = db.cursor()
|
||||
cursor.execute("INSERT INTO content (vanity, type, data) VALUES (?, ?, ?)",
|
||||
(vanity, 'url', original_url))
|
||||
db.commit()
|
||||
@app.route('/<path:path>')
|
||||
def redirect_vanity(path):
|
||||
parts = path.rstrip('/').split('/')
|
||||
vanity = parts[0]
|
||||
subpath = '/'.join(parts[1:]) if len(parts) > 1 else ''
|
||||
|
||||
return jsonify({'vanity': vanity})
|
||||
|
||||
@app.route('/<vanity>', methods=['GET'])
|
||||
def redirect_vanity(vanity):
|
||||
db = get_db()
|
||||
cursor = db.cursor()
|
||||
cursor.execute("SELECT * FROM content WHERE vanity = ?", (vanity,))
|
||||
@ -388,6 +324,12 @@ def register():
|
||||
cursor.execute("INSERT INTO users (username, password_hash) VALUES (?, ?)",
|
||||
(username, hashed_password))
|
||||
db.commit()
|
||||
|
||||
# Create user directory
|
||||
user_folder = os.path.join(app.config['UPLOAD_FOLDER'], username)
|
||||
if not os.path.exists(user_folder):
|
||||
os.makedirs(user_folder)
|
||||
|
||||
return redirect(url_for('login'))
|
||||
return render_template('register.html')
|
||||
|
||||
@ -396,12 +338,14 @@ def login():
|
||||
if request.method == 'POST':
|
||||
username = request.form['username']
|
||||
password = request.form['password']
|
||||
remember = 'remember' in request.form
|
||||
db = get_db()
|
||||
cursor = db.cursor()
|
||||
cursor.execute("SELECT * FROM users WHERE username = ?", (username,))
|
||||
user = cursor.fetchone()
|
||||
if user and User.verify_password(user[2], password):
|
||||
login_user(User(user[0], user[1], user[2]))
|
||||
user_obj = User(user[0], user[1], user[2])
|
||||
login_user(user_obj, remember=remember)
|
||||
return redirect(url_for('user_files', username=username))
|
||||
return "Invalid username or password"
|
||||
return render_template('login.html')
|
||||
@ -412,21 +356,74 @@ def logout():
|
||||
logout_user()
|
||||
return redirect(url_for('index'))
|
||||
|
||||
@app.route('/user/<username>')
|
||||
def user_files(username):
|
||||
if current_user.is_authenticated and current_user.username == username:
|
||||
user_folder = os.path.join(app.config['UPLOAD_FOLDER'], username)
|
||||
if not os.path.exists(user_folder):
|
||||
os.makedirs(user_folder)
|
||||
files = os.listdir(user_folder)
|
||||
return render_template('user_files.html', username=username, files=files)
|
||||
return "Unauthorized", 401
|
||||
@app.route('/dash/<username>')
|
||||
@app.route('/dash/<username>/')
|
||||
@app.route('/dash/<username>/<path:subpath>')
|
||||
@login_required
|
||||
def user_files(username, subpath=''):
|
||||
if current_user.username != username:
|
||||
return "Unauthorized", 401
|
||||
|
||||
user_folder = os.path.join(app.config['UPLOAD_FOLDER'], username)
|
||||
current_path = os.path.join(user_folder, subpath.rstrip('/'))
|
||||
|
||||
# Create user folder if it doesn't exist
|
||||
if not os.path.exists(user_folder):
|
||||
os.makedirs(user_folder)
|
||||
|
||||
if not os.path.exists(current_path):
|
||||
return "Folder not found", 404
|
||||
|
||||
if not os.path.isdir(current_path):
|
||||
return "Not a directory", 400
|
||||
|
||||
items = []
|
||||
folders = []
|
||||
for item in os.listdir(current_path):
|
||||
item_path = os.path.join(current_path, item)
|
||||
relative_path = os.path.relpath(item_path, user_folder)
|
||||
if os.path.isfile(item_path):
|
||||
items.append({'name': item, 'type': 'file', 'path': relative_path})
|
||||
else:
|
||||
items.append({'name': item, 'type': 'folder', 'path': relative_path})
|
||||
folders.append(relative_path)
|
||||
|
||||
parent_folder = os.path.dirname(subpath.rstrip('/')) if subpath else None
|
||||
current_folder = os.path.basename(current_path)
|
||||
|
||||
# Check if index.html exists in the current folder
|
||||
index_exists = 'index.html' in [item['name'] for item in items if item['type'] == 'file']
|
||||
|
||||
# Get the current setting for ignoring index.html
|
||||
ignore_index = session.get(f'ignore_index_{username}', False)
|
||||
|
||||
return render_template('user_files.html',
|
||||
username=username,
|
||||
items=items,
|
||||
folders=folders,
|
||||
current_path=subpath.rstrip('/'),
|
||||
parent_folder=parent_folder,
|
||||
current_folder=current_folder,
|
||||
index_exists=index_exists,
|
||||
ignore_index=ignore_index)
|
||||
|
||||
@app.route('/user/<username>/upload', methods=['POST'])
|
||||
@app.route('/dash/<username>/toggle_index')
|
||||
@login_required
|
||||
def toggle_index(username):
|
||||
if current_user.username != username:
|
||||
return "Unauthorized", 401
|
||||
|
||||
current_setting = session.get(f'ignore_index_{username}', False)
|
||||
session[f'ignore_index_{username}'] = not current_setting
|
||||
|
||||
return redirect(url_for('user_files', username=username))
|
||||
|
||||
@app.route('/dash/<username>/upload', methods=['POST'])
|
||||
@login_required
|
||||
def upload_user_file(username):
|
||||
if current_user.username != username:
|
||||
return "Unauthorized", 401
|
||||
subpath = request.form.get('subpath', '').rstrip('/')
|
||||
if 'file' not in request.files:
|
||||
return 'No file part', 400
|
||||
file = request.files['file']
|
||||
@ -434,11 +431,12 @@ def upload_user_file(username):
|
||||
return 'No selected file', 400
|
||||
if file:
|
||||
filename = secure_filename(file.filename)
|
||||
file_path = os.path.join(app.config['UPLOAD_FOLDER'], username, filename)
|
||||
file_path = os.path.join(app.config['UPLOAD_FOLDER'], username, subpath, filename)
|
||||
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||||
file.save(file_path)
|
||||
return redirect(url_for('user_files', username=username))
|
||||
return redirect(url_for('user_files', username=username, subpath=subpath))
|
||||
|
||||
@app.route('/user/<username>/delete/<filename>', methods=['POST'])
|
||||
@app.route('/dash/<username>/delete/<filename>', methods=['POST'])
|
||||
@login_required
|
||||
def delete_user_file(username, filename):
|
||||
if current_user.username != username:
|
||||
@ -448,7 +446,7 @@ def delete_user_file(username, filename):
|
||||
os.remove(file_path)
|
||||
return redirect(url_for('user_files', username=username))
|
||||
|
||||
@app.route('/user/<username>/rename', methods=['POST'])
|
||||
@app.route('/dash/<username>/rename', methods=['POST'])
|
||||
@login_required
|
||||
def rename_user_file(username):
|
||||
if current_user.username != username:
|
||||
@ -461,90 +459,100 @@ def rename_user_file(username):
|
||||
os.rename(old_path, new_path)
|
||||
return redirect(url_for('user_files', username=username))
|
||||
|
||||
@app.route('/<username>')
|
||||
@app.route('/<username>/')
|
||||
@app.route('/<username>/<path:filename>')
|
||||
def serve_user_page(username, filename=None):
|
||||
print(f"Accessing user page: {username}, filename: {filename}") # Debug print
|
||||
@app.route('/dash/<username>/create_folder', methods=['POST'])
|
||||
@login_required
|
||||
def create_folder(username):
|
||||
if current_user.username != username:
|
||||
return "Unauthorized", 401
|
||||
subpath = request.form.get('subpath', '').rstrip('/')
|
||||
folder_name = secure_filename(request.form['folder_name'])
|
||||
folder_path = os.path.join(app.config['UPLOAD_FOLDER'], username, subpath, folder_name)
|
||||
if not os.path.exists(folder_path):
|
||||
os.makedirs(folder_path)
|
||||
return redirect(url_for('user_files', username=username, subpath=subpath))
|
||||
|
||||
# Check if the username exists in the database
|
||||
db = get_db()
|
||||
cursor = db.cursor()
|
||||
cursor.execute("SELECT * FROM users WHERE username = ?", (username,))
|
||||
user = cursor.fetchone()
|
||||
if not user:
|
||||
print(f"User {username} not found") # Debug print
|
||||
return "User not found", 404
|
||||
@app.route('/dash/<username>/delete_folder/<folder_name>', methods=['POST'])
|
||||
@login_required
|
||||
def delete_folder(username, folder_name):
|
||||
if current_user.username != username:
|
||||
return "Unauthorized", 401
|
||||
folder_path = os.path.join(app.config['UPLOAD_FOLDER'], username, folder_name)
|
||||
if os.path.exists(folder_path):
|
||||
shutil.rmtree(folder_path)
|
||||
return redirect(url_for('user_files', username=username))
|
||||
|
||||
user_folder = os.path.join(app.config['UPLOAD_FOLDER'], username)
|
||||
print(f"User folder path: {user_folder}") # Debug print
|
||||
|
||||
if not os.path.exists(user_folder):
|
||||
print(f"User folder does not exist for {username}") # Debug print
|
||||
os.makedirs(user_folder) # Create the folder if it doesn't exist
|
||||
@app.route('/dash/<username>/rename_folder', methods=['POST'])
|
||||
@login_required
|
||||
def rename_folder(username):
|
||||
if current_user.username != username:
|
||||
return "Unauthorized", 401
|
||||
old_foldername = request.form['old_foldername']
|
||||
new_foldername = secure_filename(request.form['new_foldername'])
|
||||
old_path = os.path.join(app.config['UPLOAD_FOLDER'], username, old_foldername)
|
||||
new_path = os.path.join(app.config['UPLOAD_FOLDER'], username, new_foldername)
|
||||
if os.path.exists(old_path):
|
||||
os.rename(old_path, new_path)
|
||||
return redirect(url_for('user_files', username=username))
|
||||
|
||||
if filename is None or filename == '':
|
||||
# Try to serve index.html
|
||||
index_path = os.path.join(user_folder, 'index.html')
|
||||
print(f"Checking for index.html at: {index_path}") # Debug print
|
||||
if os.path.exists(index_path):
|
||||
print(f"Serving index.html for {username}") # Debug print
|
||||
return send_file(index_path)
|
||||
@app.route('/dash/<username>/move_item', methods=['POST'])
|
||||
@login_required
|
||||
def move_item(username):
|
||||
if current_user.username != username:
|
||||
return "Unauthorized", 401
|
||||
item_name = request.form['item_name']
|
||||
item_type = request.form['item_type']
|
||||
destination_folder = request.form['destination_folder']
|
||||
source_path = os.path.join(app.config['UPLOAD_FOLDER'], username, item_name)
|
||||
dest_path = os.path.join(app.config['UPLOAD_FOLDER'], username, destination_folder, item_name)
|
||||
if os.path.exists(source_path):
|
||||
shutil.move(source_path, dest_path)
|
||||
return redirect(url_for('user_files', username=username))
|
||||
|
||||
@app.route('/dash/<username>/copy_item', methods=['POST'])
|
||||
@login_required
|
||||
def copy_item(username):
|
||||
if current_user.username != username:
|
||||
return "Unauthorized", 401
|
||||
item_name = request.form['item_name']
|
||||
item_type = request.form['item_type']
|
||||
destination_folder = request.form['destination_folder']
|
||||
source_path = os.path.join(app.config['UPLOAD_FOLDER'], username, item_name)
|
||||
dest_path = os.path.join(app.config['UPLOAD_FOLDER'], username, destination_folder, item_name)
|
||||
if os.path.exists(source_path):
|
||||
if item_type == 'file':
|
||||
shutil.copy2(source_path, dest_path)
|
||||
else:
|
||||
print(f"No index.html found, listing files for {username}") # Debug print
|
||||
# If no index.html, list all files
|
||||
files = os.listdir(user_folder)
|
||||
print(f"Files in {username}'s folder: {files}") # Debug print
|
||||
return render_template('user_files_public.html', username=username, files=files)
|
||||
else:
|
||||
# Serve the requested file
|
||||
file_path = os.path.join(user_folder, filename)
|
||||
print(f"Attempting to serve file: {file_path}") # Debug print
|
||||
if os.path.exists(file_path) and os.path.isfile(file_path):
|
||||
print(f"Serving file: {file_path}") # Debug print
|
||||
return send_file(file_path)
|
||||
else:
|
||||
print(f"File not found: {file_path}") # Debug print
|
||||
return "File not found", 404
|
||||
shutil.copytree(source_path, dest_path)
|
||||
return redirect(url_for('user_files', username=username))
|
||||
|
||||
@app.route('/dash/<username>/edit/<path:filename>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit_file(username, filename):
|
||||
if current_user.username != username:
|
||||
return "Unauthorized", 401
|
||||
|
||||
file_path = os.path.join(app.config['UPLOAD_FOLDER'], username, filename)
|
||||
if not os.path.exists(file_path):
|
||||
return "File not found", 404
|
||||
|
||||
if request.method == 'POST':
|
||||
content = request.form['content']
|
||||
with open(file_path, 'w') as f:
|
||||
f.write(content)
|
||||
return redirect(url_for('user_files', username=username))
|
||||
|
||||
with open(file_path, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
return render_template('edit_file.html', filename=filename, content=content)
|
||||
|
||||
@app.route('/debug/users')
|
||||
def debug_users():
|
||||
db = get_db()
|
||||
cursor = db.cursor()
|
||||
cursor.execute("SELECT username FROM users")
|
||||
cursor.execute("SELECT * FROM users")
|
||||
users = cursor.fetchall()
|
||||
|
||||
user_files = {}
|
||||
for user in users:
|
||||
username = user[0]
|
||||
user_folder = os.path.join(app.config['UPLOAD_FOLDER'], username)
|
||||
if os.path.exists(user_folder):
|
||||
user_files[username] = os.listdir(user_folder)
|
||||
else:
|
||||
user_files[username] = []
|
||||
|
||||
return jsonify(user_files)
|
||||
|
||||
@app.route('/user/<username>/edit/<path:filename>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit_file(username, filename):
|
||||
if current_user.username != username:
|
||||
return "Unauthorized", 401
|
||||
|
||||
file_path = os.path.join(app.config['UPLOAD_FOLDER'], username, filename)
|
||||
|
||||
if request.method == 'POST':
|
||||
content = request.form['content']
|
||||
with open(file_path, 'w') as file:
|
||||
file.write(content)
|
||||
return redirect(url_for('user_files', username=username))
|
||||
|
||||
if os.path.exists(file_path) and os.path.isfile(file_path):
|
||||
with open(file_path, 'r') as file:
|
||||
content = file.read()
|
||||
return render_template('edit_file.html', username=username, filename=filename, content=content)
|
||||
else:
|
||||
return "File not found", 404
|
||||
return jsonify(users)
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True, port=7123)
|
||||
app.run(debug=True)
|
||||
|
@ -2,7 +2,8 @@ CREATE TABLE IF NOT EXISTS content (
|
||||
vanity TEXT PRIMARY KEY,
|
||||
type TEXT NOT NULL,
|
||||
data TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
user_id INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
|
@ -154,24 +154,29 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Content</h1>
|
||||
{% if created_at %}
|
||||
<p>Created at: {{ created_at }}</p>
|
||||
<h2>Content</h2>
|
||||
{% if content.user_id %}
|
||||
<p>Uploaded by: {{ content.username }}</p>
|
||||
{% else %}
|
||||
<p>Uploaded by: Anonymous</p>
|
||||
{% endif %}
|
||||
{% if language %}
|
||||
<p>Detected Language: {{ language }}</p>
|
||||
<p>Created at: {{ content.created_at }}</p>
|
||||
|
||||
{% if highlighted_content %}
|
||||
<style>{{ css }}</style>
|
||||
{{ highlighted_content|safe }}
|
||||
{% elif url %}
|
||||
<p>Shortened URL: <a href="{{ url }}">{{ url }}</a></p>
|
||||
{% else %}
|
||||
<pre>{{ raw_content }}</pre>
|
||||
{% endif %}
|
||||
|
||||
{% if current_user.is_authenticated and current_user.id == content.user_id %}
|
||||
<a href="{{ url_for('edit_content', vanity=content.vanity) }}" class="btn">Edit</a>
|
||||
<form action="{{ url_for('delete_content', vanity=content.vanity) }}" method="post" style="display: inline;">
|
||||
<button type="submit" class="btn">Delete</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
<div class="button-container">
|
||||
<button id="copy-button" onclick="copyToClipboard()">Copy Raw</button>
|
||||
<a href="{{ url_for('raw_vanity', vanity=vanity) }}" target="_blank"><button>View Raw</button></a>
|
||||
</div>
|
||||
<div class="highlight">
|
||||
{% if highlighted_content %}
|
||||
{{ highlighted_content|safe }}
|
||||
{% else %}
|
||||
<pre>{{ content }}</pre>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button id="theme-toggle">Toggle Theme</button>
|
||||
|
22
templates/edit_content.html
Normal file
22
templates/edit_content.html
Normal file
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Edit Content</title>
|
||||
<style>
|
||||
/* ... (use the same style as other pages) ... */
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h2>Edit Content</h2>
|
||||
<form method="post">
|
||||
<textarea name="content" rows="10" cols="50">{{ content.data }}</textarea>
|
||||
<br>
|
||||
<input type="submit" value="Save" class="btn">
|
||||
</form>
|
||||
<a href="{{ url_for('user_files', username=current_user.username) }}" class="btn">Back to Dashboard</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -112,8 +112,13 @@
|
||||
<body>
|
||||
<div class="container">
|
||||
<nav>
|
||||
<a href="{{ url_for('login') }}">Login</a>
|
||||
<a href="{{ url_for('register') }}">Register</a>
|
||||
{% if user %}
|
||||
<a href="{{ url_for('user_files', username=user.username) }}">View Dashboard</a>
|
||||
<a href="{{ url_for('logout') }}">Logout</a>
|
||||
{% else %}
|
||||
<a href="{{ url_for('login') }}">Login</a>
|
||||
<a href="{{ url_for('register') }}">Register</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
|
||||
<div class="typewriter-container">
|
||||
|
@ -1,6 +1,68 @@
|
||||
<h2>Login</h2>
|
||||
<form method="post">
|
||||
<input type="text" name="username" placeholder="Username" required>
|
||||
<input type="password" name="password" placeholder="Password" required>
|
||||
<input type="submit" value="Login">
|
||||
</form>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Login</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
background-color: #1a1a1a;
|
||||
color: #f0f0f0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
}
|
||||
.login-container {
|
||||
background-color: #2a2a2a;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
width: 300px;
|
||||
}
|
||||
h2 {
|
||||
color: #4CAF50;
|
||||
text-align: center;
|
||||
}
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
input {
|
||||
margin: 10px 0;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #4CAF50;
|
||||
background-color: #333;
|
||||
color: #f0f0f0;
|
||||
}
|
||||
input[type="submit"] {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type="submit"]:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
label {
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="login-container">
|
||||
<h2>Login</h2>
|
||||
<form method="post">
|
||||
<input type="text" name="username" placeholder="Username" required>
|
||||
<input type="password" name="password" placeholder="Password" required>
|
||||
<label>
|
||||
<input type="checkbox" name="remember"> Remember Me
|
||||
</label>
|
||||
<input type="submit" value="Login">
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,6 +1,62 @@
|
||||
<h2>Register</h2>
|
||||
<form method="post">
|
||||
<input type="text" name="username" placeholder="Username" required>
|
||||
<input type="password" name="password" placeholder="Password" required>
|
||||
<input type="submit" value="Register">
|
||||
</form>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Register</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
background-color: #1a1a1a;
|
||||
color: #f0f0f0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
}
|
||||
.register-container {
|
||||
background-color: #2a2a2a;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
width: 300px;
|
||||
}
|
||||
h2 {
|
||||
color: #4CAF50;
|
||||
text-align: center;
|
||||
}
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
input {
|
||||
margin: 10px 0;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #4CAF50;
|
||||
background-color: #333;
|
||||
color: #f0f0f0;
|
||||
}
|
||||
input[type="submit"] {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type="submit"]:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="register-container">
|
||||
<h2>Register</h2>
|
||||
<form method="post">
|
||||
<input type="text" name="username" placeholder="Username" required>
|
||||
<input type="password" name="password" placeholder="Password" required>
|
||||
<input type="submit" value="Register">
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,21 +1,269 @@
|
||||
<h2>{{ username }}'s Files</h2>
|
||||
<form action="{{ url_for('upload_user_file', username=username) }}" method="post" enctype="multipart/form-data">
|
||||
<input type="file" name="file" required>
|
||||
<input type="submit" value="Upload">
|
||||
</form>
|
||||
<ul>
|
||||
{% for file in files %}
|
||||
<li>
|
||||
{{ file }}
|
||||
<form action="{{ url_for('delete_user_file', username=username, filename=file) }}" method="post" style="display: inline;">
|
||||
<input type="submit" value="Delete">
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{ username }}'s Dashboard</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
background-color: #1a1a1a;
|
||||
color: #f0f0f0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.container {
|
||||
max-width: 800px;
|
||||
width: 100%;
|
||||
}
|
||||
h2, h3 {
|
||||
color: #4CAF50;
|
||||
text-align: center;
|
||||
}
|
||||
nav {
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
nav a, .btn {
|
||||
display: inline-block;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 8px 12px;
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
margin: 0 5px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
}
|
||||
nav a:hover, .btn:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
form {
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
input[type="text"], input[type="file"] {
|
||||
padding: 8px;
|
||||
margin-right: 10px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #4CAF50;
|
||||
background-color: #333;
|
||||
color: #f0f0f0;
|
||||
}
|
||||
.file-list {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
.file-item {
|
||||
background-color: #2a2a2a;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.file-icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.file-name {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.file-actions {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
}
|
||||
.folder {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h2>{{ username }}'s Dashboard</h2>
|
||||
<nav>
|
||||
<a href="{{ url_for('index') }}">Home</a>
|
||||
<a href="{{ url_for('logout') }}">Logout</a>
|
||||
</nav>
|
||||
|
||||
<form action="{{ url_for('toggle_index', username=username) }}" method="get" style="text-align: center;">
|
||||
<label>
|
||||
<input type="checkbox" onchange="this.form.submit()" {% if ignore_index %}checked{% endif %}>
|
||||
Ignore index.html and always show file listing
|
||||
</label>
|
||||
</form>
|
||||
<form action="{{ url_for('rename_user_file', username=username) }}" method="post" style="display: inline;">
|
||||
<input type="hidden" name="old_filename" value="{{ file }}">
|
||||
<input type="text" name="new_filename" placeholder="New filename" required>
|
||||
<input type="submit" value="Rename">
|
||||
|
||||
{% if index_exists and not ignore_index %}
|
||||
<p style="text-align: center;">An index.html file exists in this folder. When viewing publicly, this file will be displayed instead of the file listing.</p>
|
||||
{% endif %}
|
||||
|
||||
<h3>Upload File</h3>
|
||||
<form action="{{ url_for('upload_user_file', username=username) }}" method="post" enctype="multipart/form-data">
|
||||
<input type="hidden" name="subpath" value="{{ current_path }}">
|
||||
<input type="file" name="file" required>
|
||||
<input type="submit" value="Upload" class="btn">
|
||||
</form>
|
||||
<a href="{{ url_for('edit_file', username=username, filename=file) }}">Edit</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<h3>Create Folder</h3>
|
||||
<form action="{{ url_for('create_folder', username=username) }}" method="post">
|
||||
<input type="hidden" name="subpath" value="{{ current_path }}">
|
||||
<input type="text" name="folder_name" placeholder="New folder name" required>
|
||||
<input type="submit" value="Create Folder" class="btn">
|
||||
</form>
|
||||
|
||||
<h3>Files and Folders</h3>
|
||||
<p style="text-align: center;">Current folder: {{ current_folder or 'Root' }}</p>
|
||||
|
||||
<ul class="file-list">
|
||||
{% if parent_folder is not none %}
|
||||
<li class="file-item folder">
|
||||
<span class="file-icon">📁</span>
|
||||
<span class="file-name">
|
||||
<a href="{{ url_for('user_files', username=username, subpath=parent_folder) }}">..</a>
|
||||
</span>
|
||||
<div class="file-actions">
|
||||
<!-- No actions for parent directory -->
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% for item in items %}
|
||||
<li class="file-item {% if item.type == 'folder' %}folder{% endif %}">
|
||||
<span class="file-icon">{% if item.type == 'folder' %}📁{% else %}📄{% endif %}</span>
|
||||
<span class="file-name">
|
||||
{% if item.type == 'folder' %}
|
||||
<a href="{{ url_for('user_files', username=username, subpath=item.path) }}">{{ item.name }}</a>
|
||||
{% else %}
|
||||
{{ item.name }}
|
||||
{% endif %}
|
||||
</span>
|
||||
<div class="file-actions">
|
||||
<button onclick="deleteItem('{{ item.name }}', '{{ item.type }}')" class="btn">Delete</button>
|
||||
<button onclick="renameItem('{{ item.name }}', '{{ item.type }}')" class="btn">Rename</button>
|
||||
<button onclick="moveItem('{{ item.name }}', '{{ item.type }}')" class="btn">Move</button>
|
||||
<button onclick="copyItem('{{ item.name }}', '{{ item.type }}')" class="btn">Copy</button>
|
||||
{% if item.type == 'file' %}
|
||||
<a href="{{ url_for('edit_file', username=username, filename=item.path) }}" class="btn">Edit</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<h3>Your Uploads</h3>
|
||||
<ul class="file-list">
|
||||
{% for upload in uploads %}
|
||||
<li class="file-item">
|
||||
<span class="file-icon">
|
||||
{% if upload.type == 'pastebin' %}📝
|
||||
{% elif upload.type == 'file' %}📄
|
||||
{% elif upload.type == 'folder' %}📁
|
||||
{% elif upload.type == 'url' %}🔗
|
||||
{% endif %}
|
||||
</span>
|
||||
<span class="file-name">
|
||||
<a href="{{ url_for('redirect_vanity', path=upload.vanity) }}">{{ upload.vanity }}</a>
|
||||
({{ upload.type }})
|
||||
</span>
|
||||
<div class="file-actions">
|
||||
{% if upload.type in ['pastebin', 'url'] %}
|
||||
<a href="{{ url_for('edit_content', vanity=upload.vanity) }}" class="btn">Edit</a>
|
||||
{% endif %}
|
||||
<form action="{{ url_for('delete_content', vanity=upload.vanity) }}" method="post" style="display: inline;">
|
||||
<button type="submit" class="btn">Delete</button>
|
||||
</form>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function deleteItem(name, type) {
|
||||
if (confirm(`Are you sure you want to delete this ${type}?`)) {
|
||||
const form = document.createElement('form');
|
||||
form.method = 'POST';
|
||||
form.action = "{{ url_for('delete_user_file', username=username, filename='') }}" + name;
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
}
|
||||
}
|
||||
|
||||
function renameItem(name, type) {
|
||||
const newName = prompt(`Enter new name for this ${type}:`, name);
|
||||
if (newName && newName !== name) {
|
||||
const form = document.createElement('form');
|
||||
form.method = 'POST';
|
||||
form.action = "{{ url_for('rename_user_file', username=username, subpath=current_path) }}";
|
||||
const oldInput = document.createElement('input');
|
||||
oldInput.type = 'hidden';
|
||||
oldInput.name = 'old_filename';
|
||||
oldInput.value = name;
|
||||
const newInput = document.createElement('input');
|
||||
newInput.type = 'hidden';
|
||||
newInput.name = 'new_filename';
|
||||
newInput.value = newName;
|
||||
form.appendChild(oldInput);
|
||||
form.appendChild(newInput);
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
}
|
||||
}
|
||||
|
||||
function moveItem(name, type) {
|
||||
const destination = prompt(`Enter destination path for this ${type}:`, '/');
|
||||
if (destination) {
|
||||
const form = document.createElement('form');
|
||||
form.method = 'POST';
|
||||
form.action = "{{ url_for('move_item', username=username, subpath=current_path) }}";
|
||||
const nameInput = document.createElement('input');
|
||||
nameInput.type = 'hidden';
|
||||
nameInput.name = 'item_name';
|
||||
nameInput.value = name;
|
||||
const typeInput = document.createElement('input');
|
||||
typeInput.type = 'hidden';
|
||||
typeInput.name = 'item_type';
|
||||
typeInput.value = type;
|
||||
const destInput = document.createElement('input');
|
||||
destInput.type = 'hidden';
|
||||
destInput.name = 'destination_folder';
|
||||
destInput.value = destination;
|
||||
form.appendChild(nameInput);
|
||||
form.appendChild(typeInput);
|
||||
form.appendChild(destInput);
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
}
|
||||
}
|
||||
|
||||
function copyItem(name, type) {
|
||||
const destination = prompt(`Enter destination path to copy this ${type}:`, '/');
|
||||
if (destination) {
|
||||
const form = document.createElement('form');
|
||||
form.method = 'POST';
|
||||
form.action = "{{ url_for('copy_item', username=username, subpath=current_path) }}";
|
||||
const nameInput = document.createElement('input');
|
||||
nameInput.type = 'hidden';
|
||||
nameInput.name = 'item_name';
|
||||
nameInput.value = name;
|
||||
const typeInput = document.createElement('input');
|
||||
typeInput.type = 'hidden';
|
||||
typeInput.name = 'item_type';
|
||||
typeInput.value = type;
|
||||
const destInput = document.createElement('input');
|
||||
destInput.type = 'hidden';
|
||||
destInput.name = 'destination_folder';
|
||||
destInput.value = destination;
|
||||
form.appendChild(nameInput);
|
||||
form.appendChild(typeInput);
|
||||
form.appendChild(destInput);
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -16,12 +16,19 @@
|
||||
h2 {
|
||||
color: #4CAF50;
|
||||
}
|
||||
ul {
|
||||
list-style-type: none;
|
||||
.file-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
li {
|
||||
margin-bottom: 10px;
|
||||
.file-item {
|
||||
background-color: #2a2a2a;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
a {
|
||||
color: #4CAF50;
|
||||
@ -30,13 +37,34 @@
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.folder {
|
||||
font-weight: bold;
|
||||
}
|
||||
.file-icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>{{ username }}'s Files</h2>
|
||||
<ul>
|
||||
<p>Current folder: {{ current_folder or 'Root' }}</p>
|
||||
|
||||
{% if parent_url is not none %}
|
||||
<p><a href="{{ parent_url }}">Parent Directory</a></p>
|
||||
{% endif %}
|
||||
|
||||
<ul class="file-list">
|
||||
{% for folder in folders %}
|
||||
<li class="file-item folder">
|
||||
<span class="file-icon">📁</span>
|
||||
<a href="{{ url_for('serve_user_page', username=username, filename=folder.path) }}">{{ folder.name }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% for file in files %}
|
||||
<li><a href="{{ url_for('download_folder_file', vanity=username, file_name=file) }}">{{ file }}</a></li>
|
||||
<li class="file-item">
|
||||
<span class="file-icon">📄</span>
|
||||
<a href="{{ url_for('serve_user_page', username=username, filename=file.path) }}">{{ file.name }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</body>
|
||||
|
@ -1,27 +0,0 @@
|
||||
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Python IDE</title><script src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/brython/3.9.0/brython_stdlib.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/codemirror.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/mode/python/python.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/addon/hint/show-hint.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/addon/hint/python-hint.js"></script><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/codemirror.min.css"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/theme/monokai.min.css"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/addon/hint/show-hint.css"><style>body{background-color:#1e1e1e;color:#d4d4d4;font-family:'Consolas','Courier New',monospace;margin:0;padding:20px}h1{color:#569cd6}#code{width:100%;height:300px}#output{width:100%;height:200px;background-color:#1e1e1e;border:1px solid #3c3c3c;padding:10px;margin-top:10px;overflow-y:auto;font-family:'Consolas','Courier New',monospace}#run-button,#save-button{background-color:#0e639c;color:white;border:none;padding:10px 20px;margin-top:10px;cursor:pointer}#run-button:hover,#save-button:hover{background-color:#1177bb}.toolbar{margin-bottom:10px}.toolbar button{background-color:#3c3c3c;color:#d4d4d4;border:none;padding:5px 10px;margin-right:5px;cursor:pointer}.toolbar button:hover{background-color:#4e4e4e}</style></head><body onload="brython()"><h1>Python IDE</h1><div class="toolbar"><button id="undo-button">Undo</button><button id="redo-button">Redo</button><button id="save-button">Save</button></div><textarea id="code" placeholder="Enter your Python code here"></textarea><br><button id="run-button">Run</button><div id="output"></div><script type="text/python">from browser import document,window
|
||||
import sys
|
||||
class _0x1234:
|
||||
def __init__(_0x5678):_0x5678._0x9abc=document["output"]
|
||||
def write(_0x5678,_0xdef0):_0x5678._0x9abc.innerHTML+=_0xdef0
|
||||
sys.stdout=_0x1234()
|
||||
sys.stderr=_0x1234()
|
||||
def _0x2345(_0x6789):
|
||||
document["output"].innerHTML=""
|
||||
_0xabcd=window.editor.getValue()
|
||||
try:exec(_0xabcd)
|
||||
except Exception as _0xef01:print(f"Error: {str(_0xef01)}")
|
||||
document["run-button"].bind("click",_0x2345)
|
||||
def _0x3456(_0x789a):window.editor.undo()
|
||||
def _0x4567(_0x89ab):window.editor.redo()
|
||||
document["undo-button"].bind("click",_0x3456)
|
||||
document["redo-button"].bind("click",_0x4567)
|
||||
def _0x5678(_0x9abc):
|
||||
_0xbcde=window.editor.getValue()
|
||||
_0xcdef=window.Blob.new([_0xbcde],{'type':'text/plain'})
|
||||
_0xdef0=window.URL.createObjectURL(_0xcdef)
|
||||
_0xef01=document.createElement('a')
|
||||
_0xef01.href=_0xdef0
|
||||
_0xef01.download='python_code.py'
|
||||
_0xef01.click()
|
||||
window.URL.revokeObjectURL(_0xdef0)
|
||||
document["save-button"].bind("click",_0x5678)</script><script>var _0x1234=CodeMirror.fromTextArea(document.getElementById("code"),{mode:"python",theme:"monokai",lineNumbers:!0,autoCloseBrackets:!0,matchBrackets:!0,indentUnit:4,tabSize:4,indentWithTabs:!1,extraKeys:{"Ctrl-Space":"autocomplete","Tab":function(_0x5678){_0x5678.somethingSelected()?_0x5678.indentSelection("add"):_0x5678.replaceSelection(_0x5678.getOption("indentWithTabs")?"\t":Array(_0x5678.getOption("indentUnit")+1).join(" "),"end","+input")}},hintOptions:{completeSingle:!1}});_0x1234.on("inputRead",function(_0x2345,_0x3456){if("+input"===_0x3456.origin){var _0x4567=_0x2345.getCursor(),_0x5678=_0x2345.getTokenAt(_0x4567);("variable"===_0x5678.type||"."===_0x5678.string)&&_0x2345.showHint({completeSingle:!1})}})</script></body></html>
|
Loading…
Reference in New Issue
Block a user