226 lines
8.8 KiB
Python
226 lines
8.8 KiB
Python
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 |