first commit
This commit is contained in:
122
pages/findings.py
Normal file
122
pages/findings.py
Normal file
@@ -0,0 +1,122 @@
|
||||
from flask import Blueprint, render_template
|
||||
from models import Finding, User
|
||||
from sqlalchemy import desc
|
||||
|
||||
findings_bp = Blueprint('findings', __name__, url_prefix='/findings')
|
||||
|
||||
@findings_bp.route('/')
|
||||
def latest_findings():
|
||||
latest = Finding.query.order_by(desc(Finding.find_time)).limit(20).all()
|
||||
# Eager load user data if needed
|
||||
user_map = {u.id: u for u in User.query.filter(User.id.in_([f.found_by for f in latest])).all()}
|
||||
return render_template('latest_findings.html', findings=latest, user_map=user_map)
|
||||
|
||||
@findings_bp.route('/<int:finding_id>')
|
||||
def finding_detail(finding_id):
|
||||
finding = Finding.query.get_or_404(finding_id)
|
||||
user = User.query.get(finding.found_by)
|
||||
return render_template('finding_detail.html', finding=finding, user=user)
|
||||
|
||||
|
||||
|
||||
import requests
|
||||
from flask import Blueprint, render_template, request, session, flash, redirect, url_for
|
||||
from datetime import datetime
|
||||
from bs4 import BeautifulSoup
|
||||
from models import db, Finding
|
||||
|
||||
|
||||
@findings_bp.route('/create', methods=['GET', 'POST'])
|
||||
def create_finding():
|
||||
if not session.get('loggedin'):
|
||||
flash("Please log in to create a finding.", "warning")
|
||||
return redirect(url_for('login.login'))
|
||||
|
||||
if request.method == 'POST':
|
||||
path = request.form.get('path', '').strip()
|
||||
lorekey = request.form.get('lorekey', '').strip()
|
||||
|
||||
# Validate inputs
|
||||
if not path and not lorekey:
|
||||
flash("Title, Path, and Lorekey are required.", "danger")
|
||||
return render_template('create_finding.html', path=path, lorekey=lorekey)
|
||||
|
||||
# Validate path exists on laminax.org (non-404)
|
||||
if path:
|
||||
try:
|
||||
path_res = requests.get(f'https://laminax.org/{path}')
|
||||
if path_res.status_code == 404:
|
||||
flash(f"The path '{path}' does not exist on laminax.org.", "danger")
|
||||
return render_template('create_finding.html', path=path, lorekey=lorekey)
|
||||
else:
|
||||
soup = BeautifulSoup(path_res.text, 'html.parser')
|
||||
for hr in soup.find_all('hr'):
|
||||
hr.replace_with('----------')
|
||||
content_text = soup.get_text(separator='\n')
|
||||
content_text = soup.get_text(separator='\n')
|
||||
# Get title element
|
||||
title = (soup.title.string if soup.title else None) or "No title found"
|
||||
# Save finding
|
||||
new_finding = Finding(
|
||||
title=f'https://laminax.org/{path}',
|
||||
path=f'https://laminax.org/{path}',
|
||||
find_time=datetime.utcnow(),
|
||||
found_by=session.get('id'),
|
||||
content_preview=content_text
|
||||
)
|
||||
db.session.add(new_finding)
|
||||
db.session.commit()
|
||||
flash("Finding created successfully!", "success")
|
||||
return redirect("/findings/"+str(new_finding.id)) # Resort to manually redirecting for now
|
||||
except Exception as e:
|
||||
flash(f"Error validating path: {e}", "danger")
|
||||
return render_template('create_finding.html', path=path, lorekey=lorekey)
|
||||
|
||||
# Check lorekey with external service
|
||||
if lorekey:
|
||||
try:
|
||||
res = requests.post('https://worker.laminax.org/check-password', json={"password": lorekey})
|
||||
if res.ok:
|
||||
data = res.json()
|
||||
if data.get('redirect'):
|
||||
redirect_url = data['redirect']
|
||||
|
||||
# Fetch redirect page content
|
||||
page_res = requests.get(redirect_url)
|
||||
title = None
|
||||
if page_res.ok:
|
||||
# Parse html and replace all <hr> with 10 dashes using bs4
|
||||
soup = BeautifulSoup(page_res.text, 'html.parser')
|
||||
for hr in soup.find_all('hr'):
|
||||
hr.replace_with('----------')
|
||||
content_text = soup.get_text(separator='\n')
|
||||
# Get title element
|
||||
title = (soup.title.string if soup.title else None) or "No title found"
|
||||
else:
|
||||
content_text = None
|
||||
title = "Unable to fetch redirect page content."
|
||||
|
||||
# Save finding
|
||||
new_finding = Finding(
|
||||
title=redirect_url,
|
||||
path=redirect_url,
|
||||
find_time=datetime.utcnow(),
|
||||
found_by=session.get('id'),
|
||||
content_preview=content_text
|
||||
)
|
||||
db.session.add(new_finding)
|
||||
db.session.commit()
|
||||
flash("Finding created successfully!", "success")
|
||||
return redirect(url_for('findings.finding_detail', finding_id=new_finding.id))
|
||||
else:
|
||||
flash("Lorekey check failed or no redirect returned.", "danger")
|
||||
elif res.status_code == 401:
|
||||
flash("Invalid Lorekey provided.", "danger")
|
||||
else:
|
||||
flash("Lorekey service error, try again later.", "danger")
|
||||
except Exception as e:
|
||||
flash(f"An error occurred: {e}", "danger")
|
||||
|
||||
# GET or fallback render
|
||||
return render_template('create_finding.html')
|
||||
|
||||
7
pages/index.py
Normal file
7
pages/index.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from flask import Blueprint, render_template
|
||||
from models import db, User
|
||||
index_bp = Blueprint('index', __name__)
|
||||
|
||||
@index_bp.route('/')
|
||||
def index():
|
||||
return render_template('home.html',users=User.query.limit(20).all()) # or your index page template
|
||||
56
pages/login.py
Normal file
56
pages/login.py
Normal file
@@ -0,0 +1,56 @@
|
||||
from flask import Blueprint, render_template, request, redirect, url_for, session
|
||||
from werkzeug.security import check_password_hash
|
||||
from models import db, User
|
||||
|
||||
login_bp = Blueprint('login', __name__, url_prefix='/login')
|
||||
|
||||
@login_bp.route('/', methods=['GET', 'POST'])
|
||||
def login():
|
||||
if session.get('loggedin'):
|
||||
return redirect(url_for('index.index'))
|
||||
|
||||
username = ""
|
||||
username_err = ""
|
||||
password_err = ""
|
||||
login_err = ""
|
||||
|
||||
if request.method == 'POST':
|
||||
username = request.form.get('username', '').strip()
|
||||
password = request.form.get('password', '').strip()
|
||||
|
||||
if not username:
|
||||
username_err = "Please enter username."
|
||||
if not password:
|
||||
password_err = "Please enter your password."
|
||||
|
||||
if not username_err and not password_err:
|
||||
# Admin bypass (same as before) but don't do this in production!
|
||||
if False: # username == "adm" and password == "dont add this in please":
|
||||
session['loggedin'] = True
|
||||
session['id'] = -1
|
||||
session['username'] = "Admin"
|
||||
return redirect(url_for('index.index'))
|
||||
|
||||
# Query User via SQLAlchemy
|
||||
user = User.query.filter_by(username=username).first()
|
||||
|
||||
if user:
|
||||
# Here you need to store hashed passwords somewhere
|
||||
# Your User model doesn't have a password field yet, so let's assume:
|
||||
# You should add it like: password = db.Column(db.String(128), nullable=False)
|
||||
# For now, assuming you have a password attribute
|
||||
if hasattr(user, 'password') and check_password_hash(user.password, password):
|
||||
session['loggedin'] = True
|
||||
session['id'] = user.id
|
||||
session['username'] = user.username
|
||||
return redirect(url_for('index.index'))
|
||||
else:
|
||||
login_err = "Invalid username or password."
|
||||
else:
|
||||
login_err = "Invalid username or password."
|
||||
|
||||
return render_template('login.html',
|
||||
username=username,
|
||||
username_err=username_err,
|
||||
password_err=password_err,
|
||||
login_err=login_err)
|
||||
8
pages/logout.py
Normal file
8
pages/logout.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from flask import Blueprint, session, redirect, url_for
|
||||
|
||||
logout_bp = Blueprint('logout', __name__)
|
||||
|
||||
@logout_bp.route('/logout')
|
||||
def logout():
|
||||
session.clear() # Clear all session data
|
||||
return redirect(url_for('login.login')) # Redirect to login page
|
||||
28
pages/profile.py
Normal file
28
pages/profile.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from flask import Blueprint, render_template, session, redirect, url_for
|
||||
from models import User, Finding
|
||||
|
||||
profile_bp = Blueprint('profile', __name__, url_prefix='/profile')
|
||||
|
||||
@profile_bp.route('/')
|
||||
def my_findings():
|
||||
# Check if user is logged in
|
||||
if not session.get('loggedin'):
|
||||
return redirect(url_for('login.login'))
|
||||
|
||||
user_id = session.get('id')
|
||||
user = User.query.get(user_id)
|
||||
if not user:
|
||||
return redirect(url_for('login.login'))
|
||||
|
||||
# Get all findings by this user, exclude content_preview
|
||||
findings = Finding.query.filter_by(found_by=user_id).all()
|
||||
|
||||
return render_template('profile.html', user=user, findings=findings)
|
||||
|
||||
@profile_bp.route('/get/<int:id>', methods=['GET'])
|
||||
def view_profile(id):
|
||||
user = User.query.get(id)
|
||||
if not user:
|
||||
return "User not found. Please try again later.",
|
||||
findings = Finding.query.filter_by(found_by=id).all()
|
||||
return render_template('view_profile.html', user=user, findings=findings)
|
||||
68
pages/register.py
Normal file
68
pages/register.py
Normal file
@@ -0,0 +1,68 @@
|
||||
import re
|
||||
from datetime import datetime
|
||||
from flask import Blueprint, render_template, request, redirect, url_for, flash
|
||||
from werkzeug.security import generate_password_hash
|
||||
from models import db, User
|
||||
|
||||
register_bp = Blueprint('register', __name__, url_prefix='/register')
|
||||
|
||||
@register_bp.route('/', methods=['GET', 'POST'])
|
||||
def register():
|
||||
username = ''
|
||||
password = ''
|
||||
confirm_password = ''
|
||||
username_err = ''
|
||||
password_err = ''
|
||||
confirm_password_err = ''
|
||||
|
||||
if request.method == 'POST':
|
||||
username = request.form.get('username', '').strip()
|
||||
password = request.form.get('password', '').strip()
|
||||
confirm_password = request.form.get('confirm_password', '').strip()
|
||||
|
||||
# Validate username
|
||||
if not username:
|
||||
username_err = "Please enter a username."
|
||||
elif not re.match(r'^[a-zA-Z0-9_]+$', username):
|
||||
username_err = "Username can only contain letters, numbers, and underscores."
|
||||
else:
|
||||
# Check if username already exists
|
||||
if User.query.filter_by(username=username).first():
|
||||
username_err = "This username is already taken."
|
||||
|
||||
# Validate password
|
||||
if not password:
|
||||
password_err = "Please enter a password."
|
||||
elif len(password) < 6:
|
||||
password_err = "Password must have at least 6 characters."
|
||||
|
||||
# Validate confirm password
|
||||
if not confirm_password:
|
||||
confirm_password_err = "Please confirm password."
|
||||
elif password != confirm_password:
|
||||
confirm_password_err = "Password did not match."
|
||||
|
||||
# If no errors, insert new user
|
||||
if not username_err and not password_err and not confirm_password_err:
|
||||
hashed_password = generate_password_hash(password)
|
||||
new_user = User(
|
||||
username=username,
|
||||
password=hashed_password,
|
||||
register_time=datetime.utcnow()
|
||||
)
|
||||
try:
|
||||
db.session.add(new_user)
|
||||
db.session.commit()
|
||||
flash("Registration successful! Please login.", "success")
|
||||
return redirect(url_for('login.login'))
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
flash("Oops! Something went wrong. Please try again.", "danger")
|
||||
|
||||
return render_template('register.html',
|
||||
username=username,
|
||||
password=password,
|
||||
confirm_password=confirm_password,
|
||||
username_err=username_err,
|
||||
password_err=password_err,
|
||||
confirm_password_err=confirm_password_err)
|
||||
Reference in New Issue
Block a user