Compare commits
3 Commits
807fbc2279
...
e9dc5e5056
Author | SHA1 | Date | |
---|---|---|---|
e9dc5e5056 | |||
9760fc88e4 | |||
e366d92950 |
@ -3,6 +3,5 @@ prismic is a simple messageboard made in python
|
|||||||
|
|
||||||
## Planned features
|
## Planned features
|
||||||
- [ ] user board creation
|
- [ ] user board creation
|
||||||
- [ ] markdown support
|
|
||||||
- [ ] custom profiles
|
- [ ] custom profiles
|
||||||
- [ ] moderation tools
|
- [x] moderation tools
|
@ -327,6 +327,7 @@ class Database:
|
|||||||
data = {
|
data = {
|
||||||
'id': post[0],
|
'id': post[0],
|
||||||
'content': post[3],
|
'content': post[3],
|
||||||
|
'short_content': post[3][:40] + '...' if len(post[3]) > 40 else post[3],
|
||||||
'created_at': post[4],
|
'created_at': post[4],
|
||||||
'url': f"/post/{post[0]}",
|
'url': f"/post/{post[0]}",
|
||||||
}
|
}
|
||||||
@ -389,6 +390,7 @@ class Database:
|
|||||||
data['reference'] = {
|
data['reference'] = {
|
||||||
'id': reference_post[0],
|
'id': reference_post[0],
|
||||||
'content': reference_post[3],
|
'content': reference_post[3],
|
||||||
|
'short_content': reference_post[3][:20] + '...' if len(reference_post[3]) > 20 else reference_post[3],
|
||||||
'created_at': reference_post[4]
|
'created_at': reference_post[4]
|
||||||
}
|
}
|
||||||
logger.info(f"Reference post information found for post {post[0]}.")
|
logger.info(f"Reference post information found for post {post[0]}.")
|
||||||
@ -403,6 +405,28 @@ class Database:
|
|||||||
logger.info("No reference post.")
|
logger.info("No reference post.")
|
||||||
data['reference'] = None
|
data['reference'] = None
|
||||||
|
|
||||||
|
# get post references
|
||||||
|
logger.info(f"Getting post references for post {post[0]}...")
|
||||||
|
self.cursor.execute('''
|
||||||
|
SELECT * FROM posts WHERE refence = ?
|
||||||
|
''', (post[0],))
|
||||||
|
references = self.cursor.fetchall()
|
||||||
|
|
||||||
|
if references:
|
||||||
|
data['replies'] = []
|
||||||
|
for reference in references:
|
||||||
|
reference_data = {
|
||||||
|
'id': reference[0],
|
||||||
|
'content': reference[3],
|
||||||
|
'short_content': reference[3][:20] + '...' if len(reference[3]) > 20 else reference[3],
|
||||||
|
'created_at': reference[4]
|
||||||
|
}
|
||||||
|
data['replies'].append(reference_data)
|
||||||
|
logger.info(f"Post references found for post {post[0]}.")
|
||||||
|
else:
|
||||||
|
logger.warning(f"No post references found for post {post[0]}.")
|
||||||
|
data['replies'] = []
|
||||||
|
|
||||||
logger.info(f"Post converted to dictionary.")
|
logger.info(f"Post converted to dictionary.")
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@ -539,6 +563,19 @@ class Database:
|
|||||||
logger.info(f"Boards found.")
|
logger.info(f"Boards found.")
|
||||||
# Convert boards to dictionary
|
# Convert boards to dictionary
|
||||||
boards = [{"id": board[0], "name": board[1]} for board in boards]
|
boards = [{"id": board[0], "name": board[1]} for board in boards]
|
||||||
|
boards.sort(key=lambda x: x['name'])
|
||||||
return boards
|
return boards
|
||||||
logger.warning(f"No boards found.")
|
logger.warning(f"No boards found.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def delete_post(self, post_id):
|
||||||
|
logger.info(f"Deleting post {post_id}...")
|
||||||
|
|
||||||
|
# Delete post
|
||||||
|
self.cursor.execute('''
|
||||||
|
DELETE FROM posts WHERE id = ?
|
||||||
|
''', (post_id,))
|
||||||
|
|
||||||
|
self.connection.commit()
|
||||||
|
logger.info(f"Post {post_id} deleted.")
|
||||||
|
return True
|
@ -33,11 +33,7 @@
|
|||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
</main>
|
</main>
|
||||||
<footer>
|
<footer>
|
||||||
<p>Created by <a href="https://alfieking.dev">Alfie King</a>
|
<p>Created by <a href="https://alfieking.dev">Alfie King</a>{% if session.name %} | <a href="/logout">Logout</a>{% endif %}</p>
|
||||||
{% if session.name %}
|
|
||||||
| <a href="/logout">Logout</a>
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -12,10 +12,19 @@
|
|||||||
<h3>From {{ post.user.name }}</h3>
|
<h3>From {{ post.user.name }}</h3>
|
||||||
<h6>posted at {{ post.created_at }}</h6>
|
<h6>posted at {{ post.created_at }}</h6>
|
||||||
{% if post.reference %}
|
{% if post.reference %}
|
||||||
<h6><b>ref post:</b> <a href="/posts/{{ post.reference.id }}">{{ post.reference.content }}</a></h6>
|
<h6><b>ref post:</b> <a href="/posts/{{ post.reference.id }}">{{ post.reference.short_content }}</a></h6>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p>{{ post.content }}</p>
|
<p>{{ post.short_content }}</p>
|
||||||
<h6><a href="/posts/{{ post.id }}">View Post</a></h6>
|
<h6><a href="/posts/{{ post.id }}">View Post</a>
|
||||||
|
{% if post.replies|length > 0 %}
|
||||||
|
({{ post.replies|length }} replies)
|
||||||
|
{% endif %}
|
||||||
|
{% if session.name == "SYSTEM" %}
|
||||||
|
| <a href="/delete/post/{{ post.id }}">Delete</a>
|
||||||
|
{% elif session.name == post.user.name %}
|
||||||
|
| <a href="/delete/post/{{ post.id }}">Delete</a>
|
||||||
|
{% endif %}
|
||||||
|
</h6>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if board.posts|length == 0 %}
|
{% if board.posts|length == 0 %}
|
||||||
|
@ -11,10 +11,19 @@
|
|||||||
<h3>From {{ post.user.name }} in /{{ post.board.name }}/</h3>
|
<h3>From {{ post.user.name }} in /{{ post.board.name }}/</h3>
|
||||||
<h6>posted at {{ post.created_at }}</h6>
|
<h6>posted at {{ post.created_at }}</h6>
|
||||||
{% if post.reference %}
|
{% if post.reference %}
|
||||||
<h6><b>ref post:</b> <a href="/posts/{{ post.reference.id }}">{{ post.reference.content }}</a></h6>
|
<h6><b>ref post:</b> <a href="/posts/{{ post.reference.id }}">{{ post.reference.short_content if post.reference.id is not none else '[NOT FOUND]' }}</a></h6>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p>{{ post.content }}</p>
|
<p>{{ post.short_content }}</p>
|
||||||
<h6><a href="/posts/{{ post.id }}">View Post</a></h6>
|
<h6><a href="/posts/{{ post.id }}">View Post</a>
|
||||||
|
{% if post.replies|length > 0 %}
|
||||||
|
({{ post.replies|length }} replies)
|
||||||
|
{% endif %}
|
||||||
|
{% if session.name == "SYSTEM" %}
|
||||||
|
| <a href="/delete/post/{{ post.id }}">Delete</a>
|
||||||
|
{% elif session.name == post.user.name %}
|
||||||
|
| <a href="/delete/post/{{ post.id }}">Delete</a>
|
||||||
|
{% endif %}
|
||||||
|
</h6>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if posts|length == 0 %}
|
{% if posts|length == 0 %}
|
||||||
|
@ -7,15 +7,28 @@
|
|||||||
<h6><b>ref post:</b> <a href="/posts/{{ post.reference.id }}">{{ post.reference.content }}</a></h6>
|
<h6><b>ref post:</b> <a href="/posts/{{ post.reference.id }}">{{ post.reference.content }}</a></h6>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p>{{ post.content }}</p>
|
<p>{{ post.content }}</p>
|
||||||
|
{% if session.name == "SYSTEM" %}
|
||||||
|
<h6><a href="/delete/post/{{ post.id }}">Delete</a></h6>
|
||||||
|
{% elif session.name == post.user.name %}
|
||||||
|
<h6><a href="/delete/post/{{ post.id }}">Delete</a></h6>
|
||||||
|
{% endif %}
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<h3>Replies:</h3>
|
<h3>Replies:</h3>
|
||||||
|
|
||||||
<ul class="posts">
|
<ul class="posts">
|
||||||
{% for reply in post.replies %}
|
{% for reply in post.replies %}
|
||||||
<li>
|
<li>
|
||||||
<h3>From {{ reply.user.name }} in /{{ reply.board.name }}/</h3>
|
<h3>From {{ reply.user.name }} in /{{ reply.board.name }}/</h3>
|
||||||
<h6>posted at {{ reply.created_at }}</h6>
|
<h6>posted at {{ reply.created_at }}</h6>
|
||||||
<p>{{ reply.content }}</p>
|
<p>{{ reply.short_content }}</p>
|
||||||
<h6><a href="/posts/{{ reply.id }}">View Reply</a></h6>
|
<h6><a href="/posts/{{ reply.id }}">View Reply</a>
|
||||||
|
{% if session.name == "SYSTEM" %}
|
||||||
|
| <a href="/delete/post/{{ reply.id }}">Delete</a>
|
||||||
|
{% elif session.name == post.user.name %}
|
||||||
|
| <a href="/delete/post/{{ reply.id }}">Delete</a>
|
||||||
|
{% endif %}
|
||||||
|
</h6>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if post.replies|length == 0 %}
|
{% if post.replies|length == 0 %}
|
||||||
|
@ -10,10 +10,19 @@
|
|||||||
<h3>From {{ post.user.name }} in /{{ post.board.name }}/</h3>
|
<h3>From {{ post.user.name }} in /{{ post.board.name }}/</h3>
|
||||||
<h6>posted at {{ post.created_at }}</h6>
|
<h6>posted at {{ post.created_at }}</h6>
|
||||||
{% if post.reference %}
|
{% if post.reference %}
|
||||||
<h6><b>ref post:</b> <a href="/posts/{{ post.reference.id }}">{{ post.reference.content }}</a></h6>
|
<h6><b>ref post:</b> <a href="/posts/{{ post.reference.id }}">{{ post.reference.short_content }}</a></h6>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p>{{ post.content }}</p>
|
<p>{{ post.short_content }}</p>
|
||||||
<h6><a href="/posts/{{ post.id }}">View post</a></h6>
|
<h6><a href="/posts/{{ post.id }}">View post</a>
|
||||||
|
{% if post.replies|length > 0 %}
|
||||||
|
({{ post.replies|length }} replies)
|
||||||
|
{% endif %}
|
||||||
|
{% if session.name == "SYSTEM" %}
|
||||||
|
| <a href="/delete/post/{{ post.id }}">Delete</a>
|
||||||
|
{% elif session.name == post.user.name %}
|
||||||
|
| <a href="/delete/post/{{ post.id }}">Delete</a>
|
||||||
|
{% endif %}
|
||||||
|
</h6>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if posts|length == 0 %}
|
{% if posts|length == 0 %}
|
||||||
|
@ -14,7 +14,16 @@
|
|||||||
<h6><b>ref post:</b> <a href="/posts/{{ post.reference.id }}">{{ post.reference.content }}</a></h6>
|
<h6><b>ref post:</b> <a href="/posts/{{ post.reference.id }}">{{ post.reference.content }}</a></h6>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p>{{ post.content }}</p>
|
<p>{{ post.content }}</p>
|
||||||
<h6><a href="/posts/{{ post.id }}">View Post</a></h6>
|
<h6><a href="/posts/{{ post.id }}">View Post</a>
|
||||||
|
{% if post.replies|length > 0 %}
|
||||||
|
({{ post.replies|length }} replies)
|
||||||
|
{% endif %}
|
||||||
|
{% if session.name == "SYSTEM" %}
|
||||||
|
| <a href="/delete/post/{{ post.id }}">Delete</a>
|
||||||
|
{% elif session.name == post.user.name %}
|
||||||
|
| <a href="/delete/post/{{ post.id }}">Delete</a>
|
||||||
|
{% endif %}
|
||||||
|
</h6>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if user.posts|length == 0 %}
|
{% if user.posts|length == 0 %}
|
||||||
|
88
src/main.py
88
src/main.py
@ -1,13 +1,12 @@
|
|||||||
from flask import Flask, request, render_template, session, redirect
|
from flask import Flask, request, render_template, session, redirect
|
||||||
import database, logging, os, hashlib, html
|
import database, logging, os, hashlib
|
||||||
from flask_session import Session
|
from flask_session import Session
|
||||||
|
|
||||||
|
|
||||||
# Global variables
|
# Global variables
|
||||||
SYSTEMUID = None
|
SYSTEMUID = None
|
||||||
SYSTEMBID = None
|
SYSTEMBID = None
|
||||||
allowed_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%£^&()-_=+[]{};:'\",.<>?/\\|`~ "
|
ALLOWED_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%£^&()-_=+[]{};:'\",.<>?/\\|`~ \n"
|
||||||
|
|
||||||
|
|
||||||
# Configure logging
|
# Configure logging
|
||||||
console_log = logging.StreamHandler()
|
console_log = logging.StreamHandler()
|
||||||
@ -17,6 +16,29 @@ logger.addHandler(console_log)
|
|||||||
logger.setLevel(logging.INFO)
|
logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
|
# Helper functions
|
||||||
|
def sanitize_input(input_string):
|
||||||
|
logger.info("Sanitizing input...")
|
||||||
|
# Sanitize input to allow only certain characters
|
||||||
|
if not isinstance(input_string, str):
|
||||||
|
logger.error("Input is not a string.")
|
||||||
|
return None
|
||||||
|
sanitized = ''.join(c for c in input_string if c in ALLOWED_CHARS)
|
||||||
|
logger.info("Sanitized input")
|
||||||
|
return sanitized
|
||||||
|
|
||||||
|
|
||||||
|
def hash_password(password):
|
||||||
|
logger.info("Hashing password...")
|
||||||
|
# Hash the password using SHA-256
|
||||||
|
if not isinstance(password, str):
|
||||||
|
logger.error("Password is not a string.")
|
||||||
|
return None
|
||||||
|
hashed = hashlib.sha256(password.encode()).hexdigest()
|
||||||
|
logger.info("Hashed password")
|
||||||
|
return hashed
|
||||||
|
|
||||||
|
|
||||||
# Initialize Flask app
|
# Initialize Flask app
|
||||||
logger.info("Initializing Flask app...")
|
logger.info("Initializing Flask app...")
|
||||||
app = Flask(__name__, template_folder=os.getenv('TEMPLATE_FOLDER', 'html'), static_folder=os.getenv('STATIC_FOLDER', 'static'))
|
app = Flask(__name__, template_folder=os.getenv('TEMPLATE_FOLDER', 'html'), static_folder=os.getenv('STATIC_FOLDER', 'static'))
|
||||||
@ -34,7 +56,11 @@ if db.get_user('SYSTEM') is None:
|
|||||||
logger.info("Running first time setup...")
|
logger.info("Running first time setup...")
|
||||||
|
|
||||||
logger.info("Creating SYSTEM user...")
|
logger.info("Creating SYSTEM user...")
|
||||||
db.create_user('SYSTEM', 'SYSTEM')
|
password = os.getenv('SYSTEM_PASSWORD', None)
|
||||||
|
if password is None:
|
||||||
|
password = os.urandom(16).hex()
|
||||||
|
logger.info("Generated password for SYSTEM user: %s", password)
|
||||||
|
db.create_user('SYSTEM', hash_password(password))
|
||||||
SYSTEMUID = db.get_user('SYSTEM')[0]
|
SYSTEMUID = db.get_user('SYSTEM')[0]
|
||||||
logger.info("SYSTEM user created with UID: %s", SYSTEMUID)
|
logger.info("SYSTEM user created with UID: %s", SYSTEMUID)
|
||||||
|
|
||||||
@ -62,31 +88,6 @@ else:
|
|||||||
logger.info("Database initialized.")
|
logger.info("Database initialized.")
|
||||||
|
|
||||||
|
|
||||||
# Helper functions
|
|
||||||
|
|
||||||
def sanitize_input(input_string):
|
|
||||||
logger.info("Sanitizing input...")
|
|
||||||
# Sanitize input to allow only certain characters
|
|
||||||
if not isinstance(input_string, str):
|
|
||||||
logger.error("Input is not a string.")
|
|
||||||
return None
|
|
||||||
sanitized = ''.join(c for c in input_string if c in allowed_chars)
|
|
||||||
sanitized = html.escape(sanitized)
|
|
||||||
logger.info("Sanitized input")
|
|
||||||
return sanitized
|
|
||||||
|
|
||||||
|
|
||||||
def hash_password(password):
|
|
||||||
logger.info("Hashing password...")
|
|
||||||
# Hash the password using SHA-256
|
|
||||||
if not isinstance(password, str):
|
|
||||||
logger.error("Password is not a string.")
|
|
||||||
return None
|
|
||||||
hashed = hashlib.sha256(password.encode()).hexdigest()
|
|
||||||
logger.info("Hashed password")
|
|
||||||
return hashed
|
|
||||||
|
|
||||||
|
|
||||||
# Define routes
|
# Define routes
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
@ -339,6 +340,35 @@ def register():
|
|||||||
return render_template('register.html')
|
return render_template('register.html')
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/delete/post/<int:post_id>', methods=['GET'])
|
||||||
|
def delete_post(post_id):
|
||||||
|
logger.info("Deleting post ID: %s", post_id)
|
||||||
|
token = session.get('session')
|
||||||
|
if not token:
|
||||||
|
logger.error("Session token is missing.")
|
||||||
|
return "Session expired. Please log in again.", 403
|
||||||
|
|
||||||
|
user = db.get_session(token)
|
||||||
|
if user is None:
|
||||||
|
logger.error("Session not found or expired.")
|
||||||
|
return "Session expired. Please log in again.", 403
|
||||||
|
|
||||||
|
user_id = user[0]
|
||||||
|
post = db.get_post(post_id)
|
||||||
|
if post is None:
|
||||||
|
logger.error("Post not found: %s", post_id)
|
||||||
|
return "Post not found", 404
|
||||||
|
|
||||||
|
if post[1] != user_id and user_id != SYSTEMUID:
|
||||||
|
logger.error("User %s is not allowed to delete this post.", user_id)
|
||||||
|
return "You are not allowed to delete this post.", 403
|
||||||
|
|
||||||
|
db.delete_post(post_id)
|
||||||
|
logger.info("Post ID %s deleted successfully.", post_id)
|
||||||
|
|
||||||
|
return redirect('/posts')
|
||||||
|
|
||||||
|
|
||||||
# Main function
|
# Main function
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
logger.info("Starting Flask app...")
|
logger.info("Starting Flask app...")
|
||||||
|
@ -179,4 +179,8 @@ div#nav {
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
white-space:pre;
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user