Compare commits

..

14 Commits

Author SHA1 Message Date
0x01fe
c3f7cd5ac7 forgot to remove the endpoint 2024-07-11 15:35:23 -05:00
0x01fe
9cdd5f3da4 removed writing page 2024-07-11 15:34:59 -05:00
0x01fe
abc4574988 refactored how comments are handled to fit in with the posts class 2024-07-01 10:30:42 -05:00
0x01fe
8712b8734e fixed most endpoints 2024-07-01 09:52:38 -05:00
0x01fe
2542b6862c added some checks for user/comments files 2024-07-01 09:41:30 -05:00
0x01fe
724e0ac3d9 consolidated some pages 2024-07-01 09:35:53 -05:00
0x01fe
8d49357074 various changes making the website look better 2024-06-28 15:40:53 -05:00
0x01FE
022f41a883 fixed some bugs that i found when deploying 2024-06-26 18:03:12 -05:00
0x01fe
e69ec565f7 fixed post links and added comment stuff to posts page 2024-06-26 16:03:47 -05:00
0x01fe
caf3a7ac32 menu pathing changes 2024-06-26 15:58:05 -05:00
0x01fe
9cd68f4048 finished up the comments/user system 2024-06-26 15:53:17 -05:00
0x01fe
ce9c995a50 Merge branch 'main' into comments 2024-06-26 14:10:02 -05:00
0x01fe
76688b2d2c started working on the comments feature 2024-04-03 13:13:48 -05:00
0x01fe
f569620fce started adding the comment thing 2024-03-27 14:50:43 -05:00
19 changed files with 610 additions and 332 deletions

6
.gitignore vendored
View File

@ -11,6 +11,12 @@ docker-compose.yaml
# Ignore images in posts # Ignore images in posts
*.jpg *.jpg
*.png *.png
# Flask Data & Config
*.ini
data
.flask_session
*.json
*.gif *.gif
# Writing # Writing

View File

@ -4,8 +4,6 @@ FROM python:3.12.2-slim-bookworm
RUN apt-get update && apt-get upgrade -y RUN apt-get update && apt-get upgrade -y
RUN groupadd -r app && useradd -r -g app app
COPY . . COPY . .
RUN python3 -m pip install --upgrade pip RUN python3 -m pip install --upgrade pip
@ -13,6 +11,4 @@ RUN python3 -m pip install -r requirements.txt
WORKDIR ./app WORKDIR ./app
USER app
CMD ["python3", "-u", "app.py"] CMD ["python3", "-u", "app.py"]

View File

@ -2,17 +2,25 @@ import os
import glob import glob
import configparser import configparser
import random import random
import base64
import datetime import datetime
import requests import requests
import flask import flask
import flask_wtf.csrf
import flask_session
import waitress import waitress
import markdown import markdown
from post import Post from post import Post
import comment
import user
app = flask.Flask(__name__, static_url_path='', static_folder='static') app = flask.Flask(__name__, static_url_path='', static_folder='static')
app.register_blueprint(comment.comments)
app.register_blueprint(user.user)
# CONFIG
CONFIG_PATH = "./config.ini" CONFIG_PATH = "./config.ini"
config = configparser.ConfigParser() config = configparser.ConfigParser()
config.read(CONFIG_PATH) config.read(CONFIG_PATH)
@ -23,11 +31,22 @@ STATUS_FILE = config['STATUS']['STATUS_FILE']
PORT = int(config['NETWORK']['PORT']) PORT = int(config['NETWORK']['PORT'])
DEV = int(config['NETWORK']['DEV']) DEV = int(config['NETWORK']['DEV'])
# CSRF Protect
app.config['SECRET_KEY'] = base64.b64decode(config["FLASK"]["SECRET"])
csrf = flask_wtf.csrf.CSRFProtect()
csrf.init_app(app)
# Session Setup
app.config['SESSION_TYPE'] = 'filesystem'
app.config['SESSION_FILE_DIR'] = './data/.flask_session/'
flask_session.Session(app)
MUSIC_API_TOKEN = config['AUTH']['MUSIC_API_TOKEN'] MUSIC_API_TOKEN = config['AUTH']['MUSIC_API_TOKEN']
MUSIC_API_URL = config['NETWORK']['MUSIC_API_URL'] MUSIC_API_URL = config['NETWORK']['MUSIC_API_URL']
statuses = {} statuses = {}
def get_posts(category_filter : str | None = None) -> list[Post]: def get_posts(category_filter : str | None = None) -> list[tuple[dict, list]]:
post_files = glob.glob(f'{POSTS_FOLDER}/*') post_files = glob.glob(f'{POSTS_FOLDER}/*')
try: try:
post_files.remove(f'{POSTS_FOLDER}/POST_TEMPLATE.md') post_files.remove(f'{POSTS_FOLDER}/POST_TEMPLATE.md')
@ -57,7 +76,12 @@ def get_posts(category_filter : str | None = None) -> list[Post]:
ordered_posts.append(most_recent) ordered_posts.append(most_recent)
posts.remove(most_recent) posts.remove(most_recent)
return reversed(ordered_posts) # Convert to dict
posts = []
for post in reversed(ordered_posts):
posts.append(post.__dict__)
return posts
def read_status_file() -> dict: def read_status_file() -> dict:
with open(STATUS_FILE, 'r', encoding='utf-8') as file: with open(STATUS_FILE, 'r', encoding='utf-8') as file:
@ -97,40 +121,57 @@ def index():
# Get posts # Get posts
posts = get_posts() posts = get_posts()
post_bodies = [] if 'username' in flask.session:
for post in posts: user = flask.session['username']
post_bodies.append(post.body) else:
user = 'Anon'
# Get status # Get status
status = get_status() status = get_status()
return flask.render_template('index.html', posts=post_bodies, status=status) # Setup Comment Form
form = comment.CommentForm()
return flask.render_template('index.html', posts=posts, status=status, form=form, user=user, title='0x01fe.net')
# Posts # Posts
@app.route('/post/<string:post_name>') @app.route('/post/<string:post_name>')
def post(post_name: str): def post(post_name: str):
for post in get_posts(): for post in get_posts():
if post.title.replace(' ', '-') == post_name: if post['title'] == post_name:
return flask.render_template('index.html', posts=[post.body], status=get_status())
if 'username' in flask.session:
user = flask.session['username']
else:
user = 'Anon'
# Setup Comment Form
form = comment.CommentForm()
return flask.render_template('index.html', posts=[post], status=get_status(), form=form, user=user, title='0x01fe.net')
flask.abort(404) flask.abort(404)
# Games Page # Category's Endpoint
@app.route('/games/') @app.route('/category/<string:category>/')
def games(): def category_filter(category: str):
# Get posts # Get posts
posts = get_posts(category_filter="games") posts = get_posts(category_filter=category)
post_bodies = [] if 'username' in flask.session:
for post in posts: user = flask.session['username']
post_bodies.append(post.body) else:
user = 'Anon'
# Get status # Get status
status = get_status() status = get_status()
return flask.render_template('games.html', posts=post_bodies, status=status) # Setup Comment Form
form = comment.CommentForm()
return flask.render_template('index.html', posts=posts, status=status, form=form, user=user, title=category.replace('-', ' '))
# Music Page # Music Page
@app.route('/music/') @app.route('/music/')
@ -139,9 +180,10 @@ def music():
# Get posts # Get posts
posts = get_posts(category_filter="music") posts = get_posts(category_filter="music")
post_bodies = [] if 'username' in flask.session:
for post in posts: user = flask.session['username']
post_bodies.append(post.body) else:
user = 'Anon'
# Get status # Get status
status = get_status() status = get_status()
@ -164,64 +206,30 @@ def music():
top_albums[album_index]['listen_time'] = hours top_albums[album_index]['listen_time'] = hours
return flask.render_template('music.html', posts=post_bodies, status=status, top_albums=top_albums) # Setup Comment Form
form = comment.CommentForm()
# Motion Pictures Page return flask.render_template('music.html', posts=posts, status=status, top_albums=top_albums, form=form, user=user)
@app.route('/motion-pictures/')
def motion_pictures():
# Get posts
posts = get_posts(category_filter="motion-pictures")
post_bodies = []
for post in posts:
post_bodies.append(post.body)
# Get status
status = get_status()
return flask.render_template('motion-pictures.html', posts=post_bodies, status=status)
# Programming Page # Programming Page
@app.route('/programming/') @app.route('/programming/')
def programming(): def programming():
# Get posts # Get posts
posts = get_posts(category_filter="programming") posts_and_comments = get_posts(category_filter="programming")
post_bodies = [] if 'username' in flask.session:
for post in posts: user = flask.session['username']
post_bodies.append(post.body) else:
user = 'Anon'
# Get status # Get status
status = get_status() status = get_status()
return flask.render_template('programming.html', posts=post_bodies, status=status) # Setup Comment Form
form = comment.CommentForm()
@app.route('/writing/')
def writing():
works = []
# Get all works in writing folder
files = glob.glob(WRITING_FOLDER + '*')
for path in files:
date: str = datetime.datetime.fromtimestamp(os.path.getctime(path)).strftime("%B %d, %Y")
name: str = path.split('/')[-1]
works.append({
'date' : date,
'name' : name,
'path' : path
})
return flask.render_template('writing.html', works=works)
return flask.render_template('programming.html', posts=posts_and_comments, form=form, user=user, status=status)
# About Page # About Page
@app.route('/about/') @app.route('/about/')

61
app/comment.py Normal file
View File

@ -0,0 +1,61 @@
import json
import os
import flask
import flask_wtf.csrf
import wtforms
COMMENTS_PATH = "./data/comments.json"
comments = flask.Blueprint('comment', __name__, template_folder='./templates')
class CommentForm(flask_wtf.FlaskForm):
textbox = wtforms.TextAreaField('Input')
@comments.route('/comment/<string:post_title>', methods=['POST'])
def comment(post_title: str):
form = CommentForm(csrf_enabled=True)
save_comment(form.textbox.data, post_title)
return flask.redirect('/')
def save_comment(content: str, post_title: str):
with open(COMMENTS_PATH, 'r') as file:
comment_data = json.loads(file.read())
# See if user is logged in, otherwise setup as anon
if 'username' in flask.session:
username = flask.session['username']
else:
username = 'Anon'
comment = {
"username" : username,
"content" : content
}
# Add comment to JSON data
if post_title in comment_data:
comment_data[post_title].append(comment)
else:
comment_data[post_title] = [comment]
# Save JSON data
with open(COMMENTS_PATH, 'w') as file:
file.write(json.dumps(comment_data))
def get_comments(post_title : int) -> list[dict]:
with open(COMMENTS_PATH, 'r') as file:
comment_data = json.loads(file.read())
if post_title in comment_data:
return comment_data[post_title]
else:
return []
# Check Comments file exists
if not os.path.exists(COMMENTS_PATH):
with open(COMMENTS_PATH, 'w+') as file:
file.write('{}')

View File

@ -1,15 +1,19 @@
import markdown import markdown
import datetime import datetime
import comment
class Post: class Post:
category : str category : str
author : str author : str
date : datetime.datetime date : datetime.datetime
date_str : str
body : str body : str
file : str file : str
title : str title : str
url : str url : str
comments : list[dict]
def __init__(self, file_path): def __init__(self, file_path):
self.file = file_path self.file = file_path
@ -19,11 +23,12 @@ class Post:
self.category = lines[1].split(":")[1].strip() self.category = lines[1].split(":")[1].strip()
self.author = lines[2].split(":")[1].strip() self.author = lines[2].split(":")[1].strip()
self.title = lines[6][2:-1] self.title = lines[6].replace('#', '').strip()
self.url = '/post/' + self.title.replace(' ', '-') self.url = '/post/' + self.title
date = lines[3].split(":")[1].strip() date = lines[3].split(":")[1].strip()
self.date = datetime.datetime.strptime(date, "%d-%m-%Y") self.date = datetime.datetime.strptime(date, "%d-%m-%Y")
self.date_str = self.date.strftime("%B %d, %Y")
self.body = markdown.markdown(f'# [{self.title}]({self.url})\n' + ''.join(lines[7:])) self.body = markdown.markdown(f'# [{self.title}]({self.url})\n' + ''.join(lines[7:]), extensions=['footnotes'])
self.comments = comment.get_comments(self.title)

View File

@ -4,6 +4,6 @@ author: author
date: date date: date
# POST # POST
## TITLE # TITLE
### DATE OR SUBTITLE ### DATE OR SUBTITLE
POST TEXT POST TEXT

View File

@ -1,146 +1,113 @@
# Project Moon # Project Moon
Needles Needles
Sally forth Rocinante! Sally forth Rocinante!
The multitude tightens its hold. The multitude tightens its hold.
# Misc # Misc
Check out [NEUPINK](https://neupink.bandcamp.com/album/swordflower-hills-killer-2)! Check out [NEUPINK](https://neupink.bandcamp.com/album/swordflower-hills-killer-2)!
Solar Sect of Mystic Wisdom Solar Sect of Mystic Wisdom
~ Nuclear Fusion ~ Nuclear Fusion
His name really is Tim. His name really is Tim.
Just wait until you see the 1 in 1000 message. Just wait until you see the 1 in 1000 message.
I'm open to suggestions on how to improve the look of the website I'm open to suggestions on how to improve the look of the website
As long as there is delusion, there is hope As long as there is delusion, there is hope
It's 510. It's 510.
Catchy Right? Catchy Right?
## TV / Movie Quotes ## TV / Movie Quotes
# Monogatari # Monogatari
I don't know everything, I only know what I know. I don't know everything, I only know what I know.
## Song Lyrics ## Song Lyrics
# Im in Your Mind by King Gizzard & The Lizard Wizard # Im in Your Mind by King Gizzard & The Lizard Wizard
Everybody's lazy when they're tired Everybody's lazy when they're tired
# Straws In The Wind by King Gizzard & The Lizard Wizard # Straws In The Wind by King Gizzard & The Lizard Wizard
Mindful of the weary inkling that is lurking Mindful of the weary inkling that is lurking
Mortal traffic lights signaling when to stay or go Mortal traffic lights signaling when to stay or go
# Automation by King Gizzard & The Lizard Wizard # Automation by King Gizzard & The Lizard Wizard
Cyber surgeon, Javascript person Cyber surgeon, Javascript person
# Gilgamesh by King Gizzard & The Lizard Wizard # Gilgamesh by King Gizzard & The Lizard Wizard
Bone-dried swamplands swallow me Bone-dried swamplands swallow me
House of dust, land of bone House of dust, land of bone
I ate dirt, I drank stone I ate dirt, I drank stone
Come on, snake, punish me Come on, snake, punish me
# The Dripping Tap by King Gizzard & The Lizard Wizard # The Dripping Tap by King Gizzard & The Lizard Wizard
Drip, drip from the tap, don't slip on the drip Drip, drip from the tap, don't slip on the drip
# Face to Face by Daft Punk # Face to Face by Daft Punk
It's amazing what you'll find face to face It's amazing what you'll find face to face
It's not hard to go the distance / When you finally get involved face to face It's not hard to go the distance / When you finally get involved face to face
# Touch by Daft Punk # Touch by Daft Punk
A tourist in a dream / A visitor, it seems / A half-forgotten song / Where do I belong? A tourist in a dream / A visitor, it seems / A half-forgotten song / Where do I belong?
# Magenta Mountian by King Gizzard & The Lizard Wizard # Magenta Mountian by King Gizzard & The Lizard Wizard
What do you mean ... You can't see it? What do you mean ... You can't see it?
I don't believe you / your eyes deceive you / better check yourself in I don't believe you / your eyes deceive you / better check yourself in
You will say I'm crazy / I will go on my way 'cause it's what I need You will say I'm crazy / I will go on my way 'cause it's what I need
I'd cross a thousand seas just to prove I'm not mad I'd cross a thousand seas just to prove I'm not mad
I thought I saw a statue blink, and a bird with no head, Land on a golden thread, I rub my eyes, What am I saying? There's nothing there I thought I saw a statue blink, and a bird with no head, Land on a golden thread, I rub my eyes, What am I saying? There's nothing there
# Armor-clad Faith by NAOKI, Arc System Works # Armor-clad Faith by NAOKI, Arc System Works
I'm a fool, I know nothing / I take the role of a silly clown I'm a fool, I know nothing / I take the role of a silly clown
All I do is embrace the wounded soul All I do is embrace the wounded soul
# Love the Subhuman Self by AISHA, Jamison Boaz, Arc System Works (Guilty Gear Strive) # Love the Subhuman Self by AISHA, Jamison Boaz, Arc System Works (Guilty Gear Strive)
So carry on, love the subhuman self So carry on, love the subhuman self
Break yourself inside out, she told me Break yourself inside out, she told me
# Symphony by NAOKI, Arc System Works (Guilty Gear Strive) # Symphony by NAOKI, Arc System Works (Guilty Gear Strive)
We're just a quirky note in the symphony We're just a quirky note in the symphony
# White Whale by Shadow Academy # White Whale by Shadow Academy
So, silent tide / Tell me which face do I show the world / And which one do I hide? So, silent tide / Tell me which face do I show the world / And which one do I hide?
# Intrasport by King Gizzard & The Lizard Wizard # Intrasport by King Gizzard & The Lizard Wizard
Dreams that sew me up like sleeping with a needle Dreams that sew me up like sleeping with a needle
Those feelings that I had are building up to something Those feelings that I had are building up to something
I feel a schism in the rhythm, now I'm running I feel a schism in the rhythm, now I'm running
My hair is liquifying My hair is liquifying
My taste buds are igniting My taste buds are igniting
# Set by King Gizzard & The Lizard Wizard # Set by King Gizzard & The Lizard Wizard
Cut the cord, kill the king and reset Cut the cord, kill the king and reset
Squeezing day into night with supernatural pressure Squeezing day into night with supernatural pressure
Right eye is the sun and left the moon's light Right eye is the sun and left the moon's light
# Swan Song by King Gizzard & The Lizard Wizard # Swan Song by King Gizzard & The Lizard Wizard
Score the music // Of your essence Score the music // Of your essence
Stars fall from their lofty places Stars fall from their lofty places
Earth has been put through her paces Earth has been put through her paces
Cosmic surgeons cut the cable Cosmic surgeons cut the cable
Make a new world if you're able Make a new world if you're able
# String Theocracy by Mili # String Theocracy by Mili
Open the curtains Open the curtains
Don't miss a moment of this experiment Don't miss a moment of this experiment
If you're going to replace me // At least have the audacity to kill me thoroughly If you're going to replace me // At least have the audacity to kill me thoroughly
What's the color of the electric sheep you see? What's the color of the electric sheep you see?
Maybe we're all cold machines Maybe we're all cold machines
# Change by King Gizzard & The Lizard Wizard # Change by King Gizzard & The Lizard Wizard
We're changing pace // Higher stakes We're changing pace // Higher stakes
So called heroes wearing fake capes So called heroes wearing fake capes
Buildings that you know // People come and go // Are a certain way Buildings that you know // People come and go // Are a certain way
And then you get the news that obliterates your view // Amputate your truths // The signifiance has changed And then you get the news that obliterates your view // Amputate your truths // The signifiance has changed
Hospital inane // Meaningless and grey // But lie within the walls and the signifiance will change Hospital inane // Meaningless and grey // But lie within the walls and the signifiance will change
What would it take for us to change the game? // Maybe our existence is signifiance in vain What would it take for us to change the game? // Maybe our existence is signifiance in vain
Is that what we consider changing? // Ah, save me
# Candles by King Gizzard & The Lizard Wizard
This little man is too hot to handle // Set the funeral on fire with the candles # Candles by King Gizzard & The Lizard Wizard
Praying to the gods at the top of a mountian // Better throwing all your pennies in a fountian This little man is too hot to handle // Set the funeral on fire with the candles
My little heart, as cold as a morgue // Let the weight of it drop like an iceberg Praying to the gods at the top of a mountian // Better throwing all your pennies in a fountian
My little heart, as cold as a morgue // Let the weight of it drop like an iceberg
# Presumptuous by King Gizzard & The Lizard Wizard
Eggshell, landmine, stepping stones // Kindred spirits at a crossroads # Presumptuous by King Gizzard & The Lizard Wizard
The world we built is on a tilt // Bottled up inside and filled with guilt Eggshell, landmine, stepping stones // Kindred spirits at a crossroads
The world we built is on a tilt // Bottled up inside and filled with guilt
# Mountians Made of Steam by Silver Mt. Zion
The angels in your palm // Sing gentle worried songs
The sweetness of our dreams // Like mountains made of steam
# God Bless our Dead Marines by Silver Mt. Zion
They put angels in the electric chair, The electric chair, the electric chair
Straight up angels in the electric chair, The electric chair, the electric chair
And no one knew or no one cared // But burning stars lit up their hair
Someone had an accident above the burning trees // While somewhere distant, peacefully // Our vulgar leaders sleep
There's fresh meat in the club tonight // God bless our dead marines
When the world is sick // Can't no one be well? // But I dreamt we was all beautiful and strong
# Cam Girl / Cage Girl by Jane Remover
I peel my eyes open, everyone knows, and nobody cares
You're biting chunks out of my face, say it's the same
# Unbirthing by Cynthoni
The sonic recreation of its death // echoing through the artificial abyss
It must be liquidated in content // for a dying population addicted to its own descrution
it is blood that greases the gears of our beloved death machines // and you will be its gasoline
# You don't even know who I am by underscores
Everybody has bad days! Don't worry! It's not the end of the world! There's always tomorrow!
Today is the worst day of my life // I think I'm in love with the cards // You're were dealt
Today is the best day of my life // I invited myself in and wore your clothes // Took your pills // Cried your makeup off
And for once, I felt just like you
# Experimental Skin by Jane Remover
Allez, allez
Come touch it, see no evil // Come touch it, see no evil
Bitches don't know what to call it, I'm like 3 and 0
I can't hear you over the band // I wanna sin, blow the city up // I wanna sin, blow the city up // I wanna sin, blow the city up
Think I became a part of you // Who care? I'm just a robot to you

View File

@ -19,6 +19,10 @@ html {
--primary20: hsla(209, 61%, 71%, 20%); --primary20: hsla(209, 61%, 71%, 20%);
--primary40: hsla(209, 61%, 71%, 40%); --primary40: hsla(209, 61%, 71%, 40%);
--secondary: hsl(277, 81%, 33%); --secondary: hsl(277, 81%, 33%);
--secondary10: hsla(277, 81%, 33%, 10%);
--secondary20: hsla(277, 81%, 33%, 20%);
--secondary30: hsla(277, 81%, 33%, 30%);
--secondary40: hsla(277, 81%, 33%, 40%);
--secondary50: hsla(277, 81%, 33%, 50%); --secondary50: hsla(277, 81%, 33%, 50%);
--accent: hsl(291, 81%, 60%); --accent: hsl(291, 81%, 60%);
--accent75: hsla(291, 81%, 60%, 75%); --accent75: hsla(291, 81%, 60%, 75%);
@ -43,7 +47,24 @@ a:hover {
color: var(--accent); color: var(--accent);
} }
blockquote {
background-color: var(--secondary10);
border-style: var(--borders-style);
border-radius: 7.5px;
padding: 0.25em;
}
.post blockquote p {
text-indent: 1.5em;
}
.post blockquote li p {
text-indent: 0;
}
li {
margin-left: 4em;
}
/* Other */ /* Other */
@ -206,6 +227,50 @@ a:hover {
text-indent: 3em; text-indent: 3em;
} }
.post-date {
float: right;
}
.comment-container {
background-color: var(--primary40);
border-style: var(--borders-style);
border-radius: var(--border-radius);
padding: 1em;
margin: 1em;
}
.comment {
background-color: var(--primary40);
border-style: var(--borders-style);
border-radius: 5px;
margin: 0.25em;
padding: 0.25em;
}
.comment h4 {
margin: 0.25em;
}
.comment p {
margin: 0.25em;
text-indent: 1em;
}
.comment-editor textarea {
width: 80%;
height: 6em;
padding: 0.75em;
border-style: solid;
border-color: var(--secondary50);
}
.comment-editor textarea:focus {
border: 3px solid var(--accent);
}
/* MUSIC */ /* MUSIC */
.albums { .albums {
height: fit-content; height: fit-content;

View File

@ -13,13 +13,13 @@
<div class="container"> <div class="container">
<!-- Sidebar --> <!-- Sidebar -->
<div class="sidebar"> <div class="sidebar">
<a href="..">Home</a><br> <a href="/"><u>Home</u></a><br>
<a href="../games/">Games</a><br> <a href="/category/games/">Games</a><br>
<a href="../music/">Music</a><br> <a href="/music/">Music</a><br>
<a href="../motion-pictures/">Motion Picture</a><br> <a href="/category/motion-pictures/">Motion Picture</a><br>
<a href="../programming/">Programming</a><br> <a href="/programming/">Programming</a><br>
<a href="/writing/">Writing</a><br> <a href="/about/">About</a><br>
<a href="."><u>About</u></a> <a href="/login/">Login</a>
</div> </div>
<!-- Main Page --> <!-- Main Page -->

View File

@ -1,34 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<header>
<link rel="shortcut icon" href="index_favicon.ico">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<title>0x01fe.net - Games</title>
</header>
<body>
<div class="header">
<h1>Games</h1>
{{ status|safe }}
</div>
<div class="container">
<!-- Sidebar -->
<div class="sidebar">
<a href="..">Home</a><br>
<a href="."><u>Games</u></a><br>
<a href="../music/">Music</a><br>
<a href="../motion-pictures/">Motion Picture</a><br>
<a href="../programming/">Programming</a><br>
<a href="/writing/">Writing</a><br>
<a href="../about/">About</a>
</div>
<!-- Main Page -->
<!-- Get it? D-Log? Like digital log? -->
<div class="dlog">
{% for post in posts %}
<div class="post">{{ post|safe }}</div>
{% endfor %}
</div>
</div>
</body>
</html>

View File

@ -3,30 +3,54 @@
<header> <header>
<link rel="shortcut icon" href="index_favicon.ico"> <link rel="shortcut icon" href="index_favicon.ico">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<title>0x01fe.net</title> <title>0x01fe.net - {{ title }}</title>
</header> </header>
<body> <body>
<div class="header"> <div class="header">
<h1>0x01fe.net</h1> <h1>{{ title }}</h1>
{{ status|safe }} {{ status|safe }}
</div> </div>
<div class="container"> <div class="container">
<!-- Sidebar --> <!-- Sidebar -->
<div class="sidebar"> <div class="sidebar">
<a href="."><u>Home</u></a><br> <a href="/"><u>Home</u></a><br>
<a href="/games/">Games</a><br> <a href="/category/games/">Games</a><br>
<a href="/music/">Music</a><br> <a href="/music/">Music</a><br>
<a href="/motion-pictures/">Motion Picture</a><br> <a href="/category/motion-pictures/">Motion Picture</a><br>
<a href="/programming/">Programming</a><br> <a href="/programming/">Programming</a><br>
<a href="/writing/">Writing</a><br> <a href="/about/">About</a><br>
<a href="/about/">About</a> <a href="/login/">Login</a>
</div> </div>
<!-- Main Page --> <!-- Main Page -->
<!-- Get it? D-Log? Like digital log? --> <!-- Get it? D-Log? Like digital log? -->
<div class="dlog"> <div class="dlog">
{% for post in posts %} {% for post in posts %}
<div class="post">{{ post|safe }}</div> <div class="post">
<div class="post-date">
{{ post.date_str }}
</div>
{{ post.body|safe }}
<div class="comment-container">
<h2>Comments</h2>
{% for comment in post.comments %}
<div class="comment">
<h4>{{ comment.username }}</h4>
<p>{{ comment.content }}</p>
</div>
{% endfor %}
{% if user %}
<div class="comment-editor">
<h4>{{ user }}</h4>
<form method="post" action="/comment/{{ post.title }}">
{{ form.hidden_tag() }}
{{ form.textbox }}
<input type="submit" value="Save">
</form>
</div>
{% endif %}
</div>
</div>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>

View File

@ -1,34 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<header>
<link rel="shortcut icon" href="index_favicon.ico">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<title>0x01fe.net - Motion Pictures</title>
</header>
<body>
<div class="header">
<h1>Motion Pictures</h1>
{{ status|safe }}
</div>
<div class="container">
<!-- Sidebar -->
<div class="sidebar">
<a href="..">Home</a><br>
<a href="../games/">Games</a><br>
<a href="../music/">Music</a><br>
<a href="."><u>Motion Picture</u></a><br>
<a href="../programming/">Programming</a><br>
<a href="/writing/">Writing</a><br>
<a href="../about/">About</a>
</div>
<!-- Main Page -->
<!-- Get it? D-Log? Like digital log? -->
<div class="dlog">
{% for post in posts %}
<div class="post">{{ post|safe }}</div>
{% endfor %}
</div>
</div>
</body>
</html>

View File

@ -13,20 +13,44 @@
<div class="container"> <div class="container">
<!-- Sidebar --> <!-- Sidebar -->
<div class="sidebar"> <div class="sidebar">
<a href="..">Home</a><br> <a href="/"><u>Home</u></a><br>
<a href="../games/">Games</a><br> <a href="/category/games/">Games</a><br>
<a href="."><u>Music</u></a><br> <a href="/music/">Music</a><br>
<a href="../motion-pictures/">Motion Picture</a><br> <a href="/category/motion-pictures/">Motion Picture</a><br>
<a href="../programming/">Programming</a><br> <a href="/programming/">Programming</a><br>
<a href="/writing/">Writing</a><br> <a href="/about/">About</a><br>
<a href="../about/">About</a> <a href="/login/">Login</a>
</div> </div>
<!-- Main Page --> <!-- Main Page -->
<!-- Get it? D-Log? Like digital log? --> <!-- Get it? D-Log? Like digital log? -->
<div class="dlog"> <div class="dlog">
{% for post in posts %} {% for post in posts %}
<div class="post">{{ post|safe }}</div> <div class="post">
<div class="post-date">
{{ post.date_str }}
</div>
{{ post.body|safe }}
<div class="comment-container">
<h2>Comments</h2>
{% for comment in post.comments %}
<div class="comment">
<h4>{{ comment.username }}</h4>
<p>{{ comment.content }}</p>
</div>
{% endfor %}
{% if user %}
<div class="comment-editor">
<h4>{{ user }}</h4>
<form method="post" action="/comment/{{ post.title }}">
{{ form.hidden_tag() }}
{{ form.textbox }}
<input type="submit" value="Save">
</form>
</div>
{% endif %}
</div>
</div>
{% endfor %} {% endfor %}
</div> </div>

View File

@ -13,20 +13,44 @@
<div class="container"> <div class="container">
<!-- Sidebar --> <!-- Sidebar -->
<div class="sidebar"> <div class="sidebar">
<a href="..">Home</a><br> <a href="/"><u>Home</u></a><br>
<a href="../games/">Games</a><br> <a href="/category/games/">Games</a><br>
<a href="../music/">Music</a><br> <a href="/music/">Music</a><br>
<a href="../motion-pictures/">Motion Picture</a><br> <a href="/category/motion-pictures/">Motion Picture</a><br>
<a href="."><u>Programming</u></a><br> <a href="/programming/">Programming</a><br>
<a href="/writing/">Writing</a><br> <a href="/about/">About</a><br>
<a href="../about/">About</a> <a href="/login/">Login</a>
</div> </div>
<!-- Main Page --> <!-- Main Page -->
<!-- Get it? D-Log? Like digital log? --> <!-- Get it? D-Log? Like digital log? -->
<div class="dlog"> <div class="dlog">
{% for post in posts %} {% for post in posts %}
<div class="post">{{ post|safe }}</div> <div class="post">
<div class="post-date">
{{ post.date_str }}
</div>
{{ post.body|safe }}
<div class="comment-container">
<h2>Comments</h2>
{% for comment in post.comments %}
<div class="comment">
<h4>{{ comment.username }}</h4>
<p>{{ comment.content }}</p>
</div>
{% endfor %}
{% if user %}
<div class="comment-editor">
<h4>{{ user }}</h4>
<form method="post" action="/comment/{{ post.title }}">
{{ form.hidden_tag() }}
{{ form.textbox }}
<input type="submit" value="Save">
</form>
</div>
{% endif %}
</div>
</div>
{% endfor %} {% endfor %}
</div> </div>

View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en">
<header>
<link rel="shortcut icon" href="index_favicon.ico">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<title>0x01fe.net - Login</title>
</header>
<body>
<div class="header">
<h1>0x01fe.net</h1>
{{ status|safe }}
</div>
<div class="container">
<!-- Sidebar -->
<div class="sidebar">
<a href="/"><u>Home</u></a><br>
<a href="/games/">Games</a><br>
<a href="/music/">Music</a><br>
<a href="/motion-pictures/">Motion Picture</a><br>
<a href="/programming/">Programming</a><br>
<a href="/about/">About</a><br>
<a href="/login/">Login</a>
</div>
<div class="dlog">
<h1>Login</h1>
<form method="post" action="/user/login/">
{{ form.hidden_tag() }}
Username: {{ form.username }} <br>
Password: {{ form.password }} <br>
<input type="submit" value="Login">
</form>
<br>
<h1>Need to Register?</h1>
<a href="/user/register/">Register</a>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="en">
<header>
<link rel="shortcut icon" href="index_favicon.ico">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<title>0x01fe.net - Register</title>
</header>
<body>
<div class="header">
<h1>0x01fe.net</h1>
{{ status|safe }}
</div>
<div class="container">
<!-- Sidebar -->
<div class="sidebar">
<a href="/"><u>Home</u></a><br>
<a href="/games/">Games</a><br>
<a href="/music/">Music</a><br>
<a href="/motion-pictures/">Motion Picture</a><br>
<a href="/programming/">Programming</a><br>
<a href="/about/">About</a><br>
<a href="/login/">Login</a>
</div>
<div class="dlog">
<h1>Register</h1>
<form method="post" action="/user/add/">
{{ form.hidden_tag() }}
Username: {{ form.username }} <br>
Password: {{ form.password }} <br>
<input type="submit" value="Register">
</form>
</div>
</div>
</body>
</html>

View File

@ -1,14 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<body>
<a href="/">home</a>
<p>
This is just a little page where I post stuff I write. I was kind of unsure if I wanted this stuff out here but I think to those who know me it could serve as an interesting view into some thoughts that I don't often express elsewhere.
</p>
<br>
<br>
{% for work in works %}
<a href="/{{ work.path }}">{{ work.name }}</a> {{ work.date }}
{% endfor %}
</body>
</html>

102
app/user.py Normal file
View File

@ -0,0 +1,102 @@
import base64
import json
import os
import flask
import flask_wtf.csrf
import wtforms
user = flask.Blueprint('user', __name__, template_folder='./templates/user')
USERS_PATH = "./data/users.json"
class RegisterUserForm(flask_wtf.FlaskForm):
username = wtforms.StringField("Username", [
wtforms.validators.Length(min=4, max=32),
wtforms.validators.DataRequired()
])
password = wtforms.PasswordField("Password", [
wtforms.validators.Length(min=8, max=64),
wtforms.validators.DataRequired()
])
class LoginUserForm(flask_wtf.FlaskForm):
username = wtforms.StringField("Username", [
wtforms.validators.DataRequired()
])
password = wtforms.PasswordField("Password", [
wtforms.validators.DataRequired()
])
@user.route('/user/add/', methods=["POST"])
def add_user():
# Get form data
form = RegisterUserForm(csrf_enabled=True)
username = form.username.data
password = form.password.data
# Read existing user data
with open(USERS_PATH, 'r') as file:
user_data = json.loads(file.read())
# check if user exists
if username in user_data:
return 'ERROR PROCESSING REQUEST - That user already exists'
# Store password / server side cookie
user_data[username] = base64.b64encode(password.encode()).decode()
flask.session['username'] = username
# Write user data
with open(USERS_PATH, 'w') as file:
file.write(json.dumps(user_data))
return flask.redirect('/')
@user.route('/user/register/')
def register_page():
form = RegisterUserForm()
return flask.render_template('register.html', form=form)
@user.route('/user/login/', methods=["POST"])
def login_user():
form = LoginUserForm(csrf_enabled=True)
username = form.username.data
password = base64.b64encode(form.password.data.encode()).decode()
# Read existing user data
with open(USERS_PATH, 'r') as file:
user_data = json.loads(file.read())
# check if user exists
if username not in user_data:
return 'ERROR PROCESSING REQUEST - Bad username OR password'
# Does password match?
if user_data[username] != password:
return 'ERROR PROCESSING REQUEST - Bad username OR password'
flask.session['username'] = username
return flask.redirect('/')
@user.route('/login/')
def login_page():
form = LoginUserForm()
return flask.render_template('login.html', form=form)
@user.route('/logout/')
def logout_user():
if 'username' in flask.session:
flask.session.pop('username')
return flask.redirect('/')
# Check User file exists
if not os.path.exists(USERS_PATH):
with open(USERS_PATH, 'w+') as file:
file.write('{}')

View File

@ -2,4 +2,6 @@ Markdown==3.5.2
Flask==2.2.3 Flask==2.2.3
waitress==2.1.2 waitress==2.1.2
Werkzeug==2.2.3 Werkzeug==2.2.3
Flask-Session==0.5.0
Flask-WTF==1.1.1
requests==2.31.0 requests==2.31.0