Compare commits

..

No commits in common. "v2" and "main" have entirely different histories.
v2 ... main

48 changed files with 289 additions and 604 deletions

41
.gitignore vendored
View File

@ -1,23 +1,18 @@
__pycache__ __pycache__
*.md *.md
!POST_TEMPLATE.md !POST_TEMPLATE.md
!README.md !README.md
docker-compose.yaml docker-compose.yaml
*.sh *.sh
*.ini *.ini
# Ignore images in posts # Ignore images in posts
*.jpg
*.png
# Flask Data & Config *.gif
*.ini
data # Writing
.flask_session writing
*.json
# Writing
writing

View File

@ -4,6 +4,8 @@ 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
@ -11,4 +13,6 @@ 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,54 +2,32 @@ 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)
WRITING_FOLDER = 'static/writing/'
POSTS_FOLDER = config['POSTS']['POSTS_FOLDER'] POSTS_FOLDER = config['POSTS']['POSTS_FOLDER']
STATUS_FILE = config['STATUS']['STATUS_FILE'] 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 = {}
header_background_images = [
"canal-banner2.jpg",
"real-greensilt-banner.png"
]
def get_posts(category_filter : str | None = None) -> list[tuple[dict, list]]: def get_posts(category_filter : str | None = None) -> list[Post]:
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')
@ -79,12 +57,7 @@ def get_posts(category_filter : str | None = None) -> list[tuple[dict, list]]:
ordered_posts.append(most_recent) ordered_posts.append(most_recent)
posts.remove(most_recent) posts.remove(most_recent)
# Convert to dict return reversed(ordered_posts)
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:
@ -117,9 +90,6 @@ def get_status() -> str:
return f'<div title="{selected_key}">{markdown.markdown(selected_status)}</div>' return f'<div title="{selected_key}">{markdown.markdown(selected_status)}</div>'
def get_header_image() -> str:
return header_background_images[random.randint(0, len(header_background_images) - 1)]
# Main Page # Main Page
@app.route('/') @app.route('/')
def index(): def index():
@ -127,59 +97,40 @@ def index():
# Get posts # Get posts
posts = get_posts() posts = get_posts()
if 'username' in flask.session: post_bodies = []
user = flask.session['username'] for post in posts:
else: post_bodies.append(post.body)
user = 'Anon'
# Get status # Get status
status = get_status() status = get_status()
# Setup Comment Form return flask.render_template('index.html', posts=post_bodies, status=status)
form = comment.CommentForm()
img = get_header_image()
return flask.render_template('index.html', posts=posts, status=status, form=form, user=user, title='0x01fe.net', header_background_image=img)
# 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'] == post_name: if post.title.replace(' ', '-') == 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)
# Category's Endpoint # Games Page
@app.route('/category/<string:category>/') @app.route('/games/')
def category_filter(category: str): def games():
# Get posts # Get posts
posts = get_posts(category_filter=category) posts = get_posts(category_filter="games")
if 'username' in flask.session: post_bodies = []
user = flask.session['username'] for post in posts:
else: post_bodies.append(post.body)
user = 'Anon'
# Get status # Get status
status = get_status() status = get_status()
# Setup Comment Form return flask.render_template('games.html', posts=post_bodies, status=status)
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/')
@ -188,10 +139,9 @@ def music():
# Get posts # Get posts
posts = get_posts(category_filter="music") posts = get_posts(category_filter="music")
if 'username' in flask.session: post_bodies = []
user = flask.session['username'] for post in posts:
else: post_bodies.append(post.body)
user = 'Anon'
# Get status # Get status
status = get_status() status = get_status()
@ -214,30 +164,64 @@ def music():
top_albums[album_index]['listen_time'] = hours top_albums[album_index]['listen_time'] = hours
# Setup Comment Form return flask.render_template('music.html', posts=post_bodies, status=status, top_albums=top_albums)
form = comment.CommentForm()
return flask.render_template('music.html', posts=posts, status=status, top_albums=top_albums, form=form, user=user) # Motion Pictures Page
@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_and_comments = get_posts(category_filter="programming") posts = get_posts(category_filter="programming")
if 'username' in flask.session: post_bodies = []
user = flask.session['username'] for post in posts:
else: post_bodies.append(post.body)
user = 'Anon'
# Get status # Get status
status = get_status() status = get_status()
# Setup Comment Form return flask.render_template('programming.html', posts=post_bodies, status=status)
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/')

View File

@ -1,64 +0,0 @@
import json
import os
import flask
import flask_wtf.csrf
import wtforms
COMMENTS_PATH = "./data/comments.json"
if not os.path.exists('./data/'):
os.mkdir('./data/')
if not os.path.exists(COMMENTS_PATH):
with open(COMMENTS_PATH, 'w+') as file:
file.write('{}')
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 []

8
app/data/comments.json Normal file
View File

@ -0,0 +1,8 @@
{
"2" : [
{
"username" : "0x01FE",
"content" : "Hello, this is an example comment!"
}
]
}

5
app/data/users.json Normal file
View File

@ -0,0 +1,5 @@
{
"users" : {
"0x01FE" : "cGFzc3dvcmQ="
}
}

View File

@ -1,19 +1,15 @@
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
@ -23,12 +19,11 @@ 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].replace('#', '').strip() self.title = lines[6][2:-1]
self.url = '/post/' + self.title self.url = '/post/' + self.title.replace(' ', '-')
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:]), extensions=['footnotes']) self.body = markdown.markdown(f'# [{self.title}]({self.url})\n' + ''.join(lines[7:]))
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

@ -101,7 +101,6 @@ 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 # Candles by King Gizzard & The Lizard Wizard
This little man is too hot to handle // Set the funeral on fire with the candles This little man is too hot to handle // Set the funeral on fire with the candles
@ -111,11 +110,3 @@ My little heart, as cold as a morgue // Let the weight of it drop like an iceber
# Presumptuous by King Gizzard & The Lizard Wizard # Presumptuous by King Gizzard & The Lizard Wizard
Eggshell, landmine, stepping stones // Kindred spirits at a crossroads Eggshell, landmine, stepping stones // Kindred spirits at a crossroads
The world we built is on a tilt // Bottled up inside and filled with guilt The world we built is on a tilt // Bottled up inside and filled with guilt
# Exctintion by King Gizzard & The Lizard Wizard
I see sullied, toxic seas, poisoned soil and felled trees / Once paradise, now wasteland / Shadow on the moon expands
Set tries chaos, but too late to to unseal our futures fate
Magenta beckons like a lighthouse / Hypnotised and pulled into a pulsar
Mirage city on the ridge / Beowulf, can you land deadstick?
Pilgrims with burnt offerings / Spacesick for the whole voyage
Metal horses on the flight/ Together, transcend this life

View File

@ -1,19 +1,19 @@
.albums { .albums {
height: 100%; height: 100%;
line-height: 0; line-height: 0;
font-size: 0; font-size: 0;
} }
.albums img { .albums img {
padding: 0 0; padding: 0 0;
margin: 0 0; margin: 0 0;
border: 0 0; border: 0 0;
} }
.body { .body {
height: 100%; height: 100%;
padding: 0 0; padding: 0 0;
margin: 0 0; margin: 0 0;
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 609 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 624 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 684 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 832 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 465 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 828 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 639 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 728 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

View File

@ -1,12 +1,12 @@
EOF Mark, EOF Mark,
Glassit-VSC, Glassit-VSC,
JSON formatter, JSON formatter,
Pylance, Pylance,
Remote - SSH, Remote - SSH,
Synthwave '84 Blues, Synthwave '84 Blues,
Trailing Spaces, Trailing Spaces,
Helm Intellisense, Helm Intellisense,
background, background,
Helium Icon Theme, Helium Icon Theme,
SQLite Viewer, SQLite Viewer,
Docker Docker

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

View File

@ -1,20 +1,25 @@
/* Global Stuff */ /* Global Stuff */
@import url('https://fonts.googleapis.com/css?family=PT%20Mono:700|PT%20Mono:400'); @import url('https://fonts.googleapis.com/css?family=PT%20Mono:700|PT%20Mono:400');
body {
font-family: 'PT Mono';
font-weight: 400;
}
h1, h2, h3, h4, h5 {
font-family: 'PT Mono';
font-weight: 700;
}
html { html {
--text: black; --text: hsl(224, 83%, 91%);
--background: white; --background: hsl(224, 31%, 23%);
/* --background: #2b2d31; */ --primary: hsl(229, 81%, 73%);
--primary: hsl(135, 100%, 15%); --primary10: hsla(209, 61%, 71%, 10%);
--primary10: hsla(0, 0%, 53%, 0.1);
--primary20: hsla(209, 61%, 71%, 20%); --primary20: hsla(209, 61%, 71%, 20%);
--primary40: hsla(0, 0%, 53%, 0.4); --primary40: hsla(209, 61%, 71%, 40%);
--secondary: hsl(277, 81%, 33%); --secondary: hsl(277, 81%, 33%);
--secondary10: hsla(277, 81%, 33%, 10%); --secondary50: hsla(277, 81%, 33%, 50%);
--secondary20: hsla(277, 81%, 33%, 20%);
--secondary30: hsla(277, 81%, 33%, 30%);
--secondary40: hsla(277, 81%, 33%, 40%);
--secondary50: hsla(0, 0%, 21%, 0.5);
--accent: hsl(291, 81%, 60%); --accent: hsl(291, 81%, 60%);
--accent75: hsla(291, 81%, 60%, 75%); --accent75: hsla(291, 81%, 60%, 75%);
--accent50: hsla(291, 81%, 60%, 50%); --accent50: hsla(291, 81%, 60%, 50%);
@ -38,43 +43,21 @@ 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 */
.header { .header {
font-family: 'PT Mono';
background-size: cover;
text-align: center; text-align: center;
margin: 2em 25%; margin: 0 30%;
padding: 3em; padding: 2em;
border-style: var(--borders-style); border-style: var(--borders-style);
border-color: #1E2022; border-color: #1E2022;
background-color: var(--background); background-color: var(--background);
border-radius: var(--border-radius); border-radius: var(--border-radius);
color: white;
} }
.header a { .header a {
@ -87,7 +70,7 @@ li {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
margin: 0px 20%; margin: 0px 5%;
border-style: var(--borders-style); border-style: var(--borders-style);
border-color: #1E2022; border-color: #1E2022;
@ -116,9 +99,8 @@ li {
/* box-shadow: -10px 10px var(--accent); */ /* box-shadow: -10px 10px var(--accent); */
/* Text Settings */ /* Text Settings */
/* font-weight: bold; */ font-weight: bold;
line-height: 30pt; line-height: 30pt;
font-family: Verdana, Geneva, Tahoma, sans-serif;
} }
.sidebar a { .sidebar a {
@ -220,55 +202,10 @@ li {
} }
.post p { .post p {
font-family: Verdana, Geneva, sans-serif;
line-height: 2.25; line-height: 2.25;
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;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 MiB

View File

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

View File

@ -1,20 +1,20 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<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='albumsquare.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='albumsquare.css') }}">
<title>Album Square</title> <title>Album Square</title>
</header> </header>
<body> <body>
<div class="albums"> <div class="albums">
{% for album in top_albums %} {% for album in top_albums %}
<a title="{{ album.album_name}} by {{ album.artist_name }} - {{ album.listen_time }} Hours"> <a title="{{ album.album_name}} by {{ album.artist_name }} - {{ album.listen_time }} Hours">
<img src="{{ album.album_cover }}" style="width: {{ res }}px; height: {{ res }}px;"> <img src="{{ album.album_cover }}" style="width: {{ res }}px; height: {{ res }}px;">
</a> </a>
{% if loop.index % limit == 0 %} {% if loop.index % limit == 0 %}
<br> <br>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</div> </div>
</body> </body>
</html> </html>

34
app/templates/games.html Normal file
View File

@ -0,0 +1,34 @@
<!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,54 +3,30 @@
<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> <title>0x01fe.net</title>
</header> </header>
<body> <body>
<div style="background-image: url({{ header_background_image }});" class="header"> <div class="header">
<h1>{{ title }}</h1> <h1>0x01fe.net</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="/category/games/">Games</a><br> <a href="/games/">Games</a><br>
<a href="/music/">Music</a><br> <a href="/music/">Music</a><br>
<a href="/category/motion-pictures/">Motion Picture</a><br> <a href="/motion-pictures/">Motion Picture</a><br>
<a href="/programming/">Programming</a><br> <a href="/programming/">Programming</a><br>
<a href="/about/">About</a><br> <a href="/writing/">Writing</a><br>
<a href="/login/">Login</a> <a href="/about/">About</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"> <div class="post">{{ post|safe }}</div>
<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

@ -0,0 +1,34 @@
<!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,44 +13,20 @@
<div class="container"> <div class="container">
<!-- Sidebar --> <!-- Sidebar -->
<div class="sidebar"> <div class="sidebar">
<a href="/"><u>Home</u></a><br> <a href="..">Home</a><br>
<a href="/category/games/">Games</a><br> <a href="../games/">Games</a><br>
<a href="/music/">Music</a><br> <a href="."><u>Music</u></a><br>
<a href="/category/motion-pictures/">Motion Picture</a><br> <a href="../motion-pictures/">Motion Picture</a><br>
<a href="/programming/">Programming</a><br> <a href="../programming/">Programming</a><br>
<a href="/about/">About</a><br> <a href="/writing/">Writing</a><br>
<a href="/login/">Login</a> <a href="../about/">About</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"> <div class="post">{{ post|safe }}</div>
<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,44 +13,20 @@
<div class="container"> <div class="container">
<!-- Sidebar --> <!-- Sidebar -->
<div class="sidebar"> <div class="sidebar">
<a href="/"><u>Home</u></a><br> <a href="..">Home</a><br>
<a href="/category/games/">Games</a><br> <a href="../games/">Games</a><br>
<a href="/music/">Music</a><br> <a href="../music/">Music</a><br>
<a href="/category/motion-pictures/">Motion Picture</a><br> <a href="../motion-pictures/">Motion Picture</a><br>
<a href="/programming/">Programming</a><br> <a href="."><u>Programming</u></a><br>
<a href="/about/">About</a><br> <a href="/writing/">Writing</a><br>
<a href="/login/">Login</a> <a href="../about/">About</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"> <div class="post">{{ post|safe }}</div>
<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

@ -1,40 +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 - 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

@ -1,36 +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 - 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

@ -0,0 +1,14 @@
<!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>

View File

@ -1,102 +0,0 @@
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,6 +2,4 @@ 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