Files
noprinter/app.py

226 lines
8.8 KiB
Python
Raw Normal View History

2026-03-18 17:27:43 +01:00
import filedb
from moderation import moderate #dummy_moderate as moderate #moderate
# Using dummy moderation for testing purposes
from flask import Flask, request, jsonify,send_file,session, redirect,url_for
from werkzeug.utils import secure_filename
import os
import secrets
app = Flask(__name__, static_folder='frontend/static', static_url_path='/static')
app.config['UPLOAD_FOLDER'] = 'uploads_temp/' # Temporary upload folder, filedb will store it anyway
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
app.secret_key = secrets.token_hex(16) # For session management
@app.route('/api/post_content/<post_id>', methods=['GET'])
def get_post_content(post_id): # Returns the content file of a post
try:
post = filedb.get_post(post_id)
if post.contentloc and os.path.isfile(post.contentloc):
return send_file(post.contentloc)
else:
return jsonify({'error': 'Content not found'}), 404
except filedb.PostNotFoundError:
return jsonify({'error': 'Post not found'}), 404
@app.route('/api/post/<post_id>', methods=['GET'])
def get_post(post_id): # Returns metadata of a post
try:
post = filedb.get_post(post_id)
return jsonify({
'id': post.id,
'title': post.title,
'content_type': post.contentType,
'tags': post.tags,
'date_created': post.dateCreated,
'creator_id': post.creator
}), 200
except filedb.PostNotFoundError:
return jsonify({'error': 'Post not found'}), 404
@app.route('/api/publish/post', methods=['POST'])
def publish_post():
if 'user_id' not in session:
return jsonify({'error': 'Authentication required'}), 401
if 'title' not in request.form or 'tags' not in request.form or 'file' not in request.files:
return jsonify({'error': 'Missing required fields'}), 400
title = request.form['title']
tags = request.form.getlist('tags')
file = request.files['file']
if file.filename == '':
return jsonify({'error': 'No selected file'}), 400
filename = secure_filename(file.filename)
temp_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
file.save(temp_path)
if not moderate(temp_path):
os.remove(temp_path)
return jsonify({'error': 'Stop uploading porn'}), 400
post_id = filedb.createPost(title, temp_path, session['user_id'], tags)
os.remove(temp_path)
return jsonify({'message': 'Post created', 'post_id': post_id}), 201
@app.route('/api/getUser/<user_id>', methods=['GET'])
def get_user(user_id):
try:
user = filedb.lookup(user_id)
return jsonify({
'id': user.id,
'username': user.username
}), 200
except FileNotFoundError:
return jsonify({'error': 'User not found'}), 404
@app.route('/api/create_post', methods=['POST'])
def create_post():
if 'user_id' not in session:
return jsonify({'error': 'Authentication required'}), 401
if 'title' not in request.form or 'tags' not in request.form or 'file' not in request.files:
return jsonify({'error': 'Missing required fields'}), 400
title = request.form['title']
tags = request.form.getlist('tags')
file = request.files['file']
if file.filename == '':
return jsonify({'error': 'No selected file'}), 400
filename = secure_filename(file.filename)
temp_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
file.save(temp_path)
if not moderate(temp_path):
os.remove(temp_path)
return jsonify({'error': 'Content failed moderation'}), 400
post_id = filedb.createPost(title, temp_path, session['user_id'], tags)
os.remove(temp_path)
return jsonify({'message': 'Post created', 'post_id': post_id}), 201
@app.route('/api/login', methods=['POST'])
def login():
if 'username' not in request.form or 'password' not in request.form:
return jsonify({'error': 'Missing username or password'}), 400
username = request.form['username']
password = request.form['password']
try:
user = filedb.lookupByUsername(username)
if filedb.verify_password(user.password_hash,password):
session['user_id'] = user.id
return jsonify({'message': 'Login successful'}), 200
else:
return jsonify({'error': 'Invalid credentials'}), 401
except FileNotFoundError:
return jsonify({'error': 'Invalid credentials'}), 401
@app.route('/api/register', methods=['POST'])
def register():
if int(request.headers.get("Content-Length",0)) > 1000:
return jsonify({'error': 'WHAT THE FUCK'}), 400
erikoer = request.get_data(parse_form_data=True) # please force form i beg
formdata = request.form.to_dict()
print(formdata) # Debugging line to see incoming form data cuz idk why it doesn't work
print(request.form) # i want to die this is a blank immutablemulti dict
print(erikoer)
if 'username' not in formdata or 'password' not in formdata:
return jsonify({'error': 'Missing username or password'}), 400
# WHAT THE FUCK
# FORMDATA IS EMPTY WTF
# DEVTOOLS SHOWS THE FORMDATA IS SENT CORRECTLY
# flask waht is wrong with you
username = formdata['username']
password = formdata['password']
try:
filedb.lookupByUsername(username)
return jsonify({'error': 'Username already taken'}), 400
except FileNotFoundError:
user_id = filedb.createUser(username,password)
session['user_id'] = user_id
return jsonify({'message': 'Registration successful', 'user_id': user_id}), 201
@app.route('/api/logout', methods=['POST'])
def logout():
session.pop('user_id', None)
return jsonify({'message': 'Logged out'}), 200
# Frontend serving
@app.route('/')
def index():
return send_file('frontend/index.html')
@app.route('/post/<post_id>')
def serve_post_page(post_id):
return send_file('frontend/post.html')
@app.route('/user/<user_id>')
def serve_user_page(user_id):
return send_file('frontend/user.html')
@app.route("/login")
@app.route("/login/")
def serve_login_page():
return send_file('frontend/login.html')
@app.route("/register")
@app.route("/register/")
def serve_register_page():
return send_file('frontend/register.html')
@app.route('/publish/post')
def serve_publish_post_page():
if 'user_id' not in session:
return redirect('/login', code=302)
return send_file('frontend/publish_post.html')
# thanks to gpt for helping me with this code and making the frontend
# Thanks to openai for the API that makes moderation possible, even if it's not used right now
## SSR endpoints cuz we need extra functionality NOW and js is too boring to write
@app.route('/ssr/usr')
def ssr_user():
out_html = "<h1>Users</h1><br>"
for user in filedb.listUsers():
out_html += f'<a href="/user/{user.id}">{user.username}</a><br><hr>'
return out_html
@app.route('/ssr/post')
def ssr_post():
out_html = "<h1>Posts</h1><br>"
for post in filedb.listPosts():
lookup = "???"
try:
lookup = filedb.lookup(post.creator).username
except:
pass
out_html += f'<a href="/post/{post.id}">{post.title}</a> by <a href="/user/{post.creator}">{lookup}</a><br><hr>'
return out_html
def has_no_empty_params(rule):
defaults = rule.defaults if rule.defaults is not None else ()
arguments = rule.arguments if rule.arguments is not None else ()
return len(defaults) >= len(arguments)
ssr_endpoint_meta = [
("/ssr/usr","List all users"),
("/ssr/post","List all posts"),
]
@app.route("/ssr/") # Get all ssr endpoints (auto generate)
def auto():
htm = "<h1>Additional stuff:</h1>"
htm += "<p>This page may seem advanced. Fear not, just use the description to navigate.</p>"
for rule in app.url_map.iter_rules():
# Filter out rules we can't navigate to in a browser
# and rules that require parameters
if "GET" in rule.methods and has_no_empty_params(rule):
if rule.endpoint.startswith("ssr_"):
url = url_for(rule.endpoint, **(rule.defaults or {}))
desc = next((desc for path,desc in ssr_endpoint_meta if path == url), "No description")
htm += f'<a href="{url}">{url}</a> - {desc}<br>'
return htm
@app.after_request
def wrap(response):
# Get the path of the request
path = request.path
if path.startswith("/ssr/") and response.content_type == "text/html; charset=utf-8":
# Wrap the response in a basic HTML structure
original_content = response.get_data(as_text=True)
with open("frontend/cont.html","r",encoding="utf-8") as f:
cont_html = f.read()
new_content = cont_html.replace("<!--ReplaceWithContent-->", original_content)
response.set_data(new_content)
return response