Compare commits

...

21 Commits

Author SHA1 Message Date
2b466e98ef removed all css and comments stuff 2025-01-30 11:08:45 -06:00
e747749e70 did stuff 2025-01-29 09:25:06 -06:00
0x01FE
4dc412d9be removed all(?) of the comments stuff 2025-01-29 09:01:05 -06:00
c2f829d39b new css stuff 2024-09-17 10:16:26 -05:00
654a87b877 gitignore update 2024-09-17 09:50:03 -05:00
0x01FE
ad2175e6cb added all my images and stuff 2024-09-17 09:45:25 -05:00
0x01FE
637e7bd9ab starting new css (again) 2024-09-14 17:01:26 -05:00
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
52 changed files with 601 additions and 385 deletions

11
.gitignore vendored
View File

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

View File

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

View File

@ -1,11 +1,11 @@
import os
import glob
import configparser
import random
import datetime
import base64
import requests
import flask
import flask_wtf.csrf
import waitress
import markdown
@ -13,21 +13,31 @@ from post import Post
app = flask.Flask(__name__, static_url_path='', static_folder='static')
# CONFIG
CONFIG_PATH = "./config.ini"
config = configparser.ConfigParser()
config.read(CONFIG_PATH)
WRITING_FOLDER = 'static/writing/'
POSTS_FOLDER = config['POSTS']['POSTS_FOLDER']
STATUS_FILE = config['STATUS']['STATUS_FILE']
PORT = int(config['NETWORK']['PORT'])
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)
MUSIC_API_TOKEN = config['AUTH']['MUSIC_API_TOKEN']
MUSIC_API_URL = config['NETWORK']['MUSIC_API_URL']
statuses = {}
header_background_images = [
"canal-banner2.jpg",
"real-greensilt-banner.png"
]
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}/*')
try:
post_files.remove(f'{POSTS_FOLDER}/POST_TEMPLATE.md')
@ -57,7 +67,12 @@ def get_posts(category_filter : str | None = None) -> list[Post]:
ordered_posts.append(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:
with open(STATUS_FILE, 'r', encoding='utf-8') as file:
@ -90,6 +105,9 @@ def get_status() -> str:
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
@app.route('/')
def index():
@ -97,40 +115,35 @@ def index():
# Get posts
posts = get_posts()
post_bodies = []
for post in posts:
post_bodies.append(post.body)
# Get status
status = get_status()
return flask.render_template('index.html', posts=post_bodies, status=status)
img = get_header_image()
return flask.render_template('index.html', posts=posts, status=status, title='0x01fe.net', header_background_image=img)
# Posts
@app.route('/post/<string:post_name>')
def post(post_name: str):
for post in get_posts():
if post.title.replace(' ', '-') == post_name:
return flask.render_template('index.html', posts=[post.body], status=get_status())
if post['title'] == post_name:
return flask.render_template('index.html', posts=[post], status=get_status(), title='0x01fe.net')
flask.abort(404)
# Games Page
@app.route('/games/')
def games():
# Category's Endpoint
@app.route('/category/<string:category>/')
def category_filter(category: str):
# Get posts
posts = get_posts(category_filter="games")
post_bodies = []
for post in posts:
post_bodies.append(post.body)
posts = get_posts(category_filter=category)
# Get status
status = get_status()
return flask.render_template('games.html', posts=post_bodies, status=status)
return flask.render_template('index.html', posts=posts, status=status, title=category.replace('-', ' '))
# Music Page
@app.route('/music/')
@ -139,10 +152,6 @@ def music():
# Get posts
posts = get_posts(category_filter="music")
post_bodies = []
for post in posts:
post_bodies.append(post.body)
# Get status
status = get_status()
@ -164,64 +173,20 @@ def music():
top_albums[album_index]['listen_time'] = hours
return flask.render_template('music.html', posts=post_bodies, status=status, top_albums=top_albums)
# 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)
return flask.render_template('music.html', posts=posts, status=status, top_albums=top_albums)
# Programming Page
@app.route('/programming/')
def programming():
# Get posts
posts = get_posts(category_filter="programming")
post_bodies = []
for post in posts:
post_bodies.append(post.body)
posts_and_comments = get_posts(category_filter="programming")
# Get status
status = get_status()
return flask.render_template('programming.html', posts=post_bodies, status=status)
@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, status=status)
# About Page
@app.route('/about/')

64
app/comment.py Normal file
View File

@ -0,0 +1,64 @@
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 []

View File

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

View File

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

View File

@ -6,6 +6,7 @@ class Post:
category : str
author : str
date : datetime.datetime
date_str : str
body : str
file : str
title : str
@ -19,11 +20,11 @@ class Post:
self.category = lines[1].split(":")[1].strip()
self.author = lines[2].split(":")[1].strip()
self.title = lines[6][2:-1]
self.url = '/post/' + self.title.replace(' ', '-')
self.title = lines[6].replace('#', '').strip()
self.url = '/post/' + self.title
date = lines[3].split(":")[1].strip()
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'])

View File

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

View File

@ -101,6 +101,7 @@ 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
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
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
@ -110,3 +111,11 @@ My little heart, as cold as a morgue // Let the weight of it drop like an iceber
# Presumptuous by King Gizzard & The Lizard Wizard
Eggshell, landmine, stepping stones // Kindred spirits at a crossroads
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 624 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 828 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 728 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

BIN
app/static/render.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

BIN
app/static/roland_think.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

View File

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

42
app/static/style2.css Normal file
View File

@ -0,0 +1,42 @@
@import url('https://fonts.googleapis.com/css?family=PT%20Mono:700|PT%20Mono:400');
.post img {
width: 50%;
margin-left: auto;
margin-right: auto;
display: block;
}
.header {
font-family: 'PT Mono';
background-size: cover;
text-align: center;
color: white;
padding: 2em;
}
.sidebar {
margin: 1em 0;
padding: 0.5em;
font-family: Verdana, Geneva, Tahoma, sans-serif;
}
.post h1 {
font-family: Georgia, 'Times New Roman', Times, serif;
font-weight: 100;
font-size: 26px;
}
.post h2 {
font-family: Georgia, 'Times New Roman', Times, serif;
font-weight: 300;
font-size: 18px;
}
.post {
margin-bottom: 8em;
}
.post-date {
float: right;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
app/static/yosemite.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 MiB

View File

@ -2,28 +2,21 @@
<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 - About</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style2.css') }}">
<title>0x01fe.net - {{ title }}</title>
</header>
<body>
<div class="header">
<h1>0x01fe.net</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="../motion-pictures/">Motion Picture</a><br>
<a href="../programming/">Programming</a><br>
<a href="/writing/">Writing</a><br>
<a href="."><u>About</u></a>
</div>
<!-- Main Page -->
<!-- Get it? D-Log? Like digital log? -->
<h1>{{ title }}</h1>
<p>{{ status|safe }}</p>
<h1>Stuff</h1>
<ul class="sidebar">
<li><a href="/"><u>Home</u></a></li>
<li><a href="/category/games/">Games</a></li>
<li><a href="/music/">Music</a></li>
<li><a href="/category/motion-pictures/">Motion Picture</a></li>
<li><a href="/programming/">Programming</a></li>
<li><a href="/about/">About</a></li>
</ul>
<div class="dlog">
<div class="post">
<h2>About</h2>
@ -37,6 +30,5 @@
</p>
</div>
</div>
</div>
</body>
</html>

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

@ -2,33 +2,28 @@
<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</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style2.css') }}">
<title>0x01fe.net - {{ title }}</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="/writing/">Writing</a><br>
<a href="/about/">About</a>
</div>
<!-- Main Page -->
<!-- Get it? D-Log? Like digital log? -->
<div class="dlog">
<h1>{{ title }}</h1>
<p>{{ status|safe }}</p>
<h1>Stuff</h1>
<ul class="sidebar">
<li><a href="/"><u>Home</u></a></li>
<li><a href="/category/games/">Games</a></li>
<li><a href="/music/">Music</a></li>
<li><a href="/category/motion-pictures/">Motion Picture</a></li>
<li><a href="/programming/">Programming</a></li>
<li><a href="/about/">About</a></li>
</ul>
{% 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>
{% endfor %}
</div>
</div>
</body>
</html>

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

@ -2,31 +2,32 @@
<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 - Music</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style2.css') }}">
<title>0x01fe.net - {{ title }}</title>
</header>
<body>
<div class="header">
<h1>Music</h1>
{{ status|safe }}
</div>
<div class="container">
<!-- Sidebar -->
<div class="sidebar">
<a href="..">Home</a><br>
<a href="../games/">Games</a><br>
<a href="."><u>Music</u></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>
<h1>{{ title }}</h1>
<p>{{ status|safe }}</p>
<h1>Stuff</h1>
<ul class="sidebar">
<li><a href="/"><u>Home</u></a></li>
<li><a href="/category/games/">Games</a></li>
<li><a href="/music/">Music</a></li>
<li><a href="/category/motion-pictures/">Motion Picture</a></li>
<li><a href="/programming/">Programming</a></li>
<li><a href="/about/">About</a></li>
</ul>
<!-- Main Page -->
<!-- Get it? D-Log? Like digital log? -->
<div class="dlog">
{% 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>
{% endfor %}
</div>
@ -43,6 +44,5 @@
{% endfor %}
</div>
</div>
</div>
</body>
</html>

View File

@ -2,31 +2,31 @@
<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 - Programming</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style2.css') }}">
<title>0x01fe.net - {{ title }}</title>
</header>
<body>
<div class="header">
<h1>Programming</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="../motion-pictures/">Motion Picture</a><br>
<a href="."><u>Programming</u></a><br>
<a href="/writing/">Writing</a><br>
<a href="../about/">About</a>
</div>
<h1>{{ title }}</h1>
<p>{{ status|safe }}</p>
<h1>Stuff</h1>
<ul class="sidebar">
<li><a href="/"><u>Home</u></a></li>
<li><a href="/category/games/">Games</a></li>
<li><a href="/music/">Music</a></li>
<li><a href="/category/motion-pictures/">Motion Picture</a></li>
<li><a href="/programming/">Programming</a></li>
<li><a href="/about/">About</a></li>
</ul>
<!-- Main Page -->
<!-- Get it? D-Log? Like digital log? -->
<div class="dlog">
{% 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>
{% endfor %}
</div>
@ -35,6 +35,5 @@
<h2>Other</h2>
<a href="">Technologies I Use</a>
</div>
</div>
</body>
</html>

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
waitress==2.1.2
Werkzeug==2.2.3
Flask-Session==0.5.0
Flask-WTF==1.1.1
requests==2.31.0