major update

This commit is contained in:
2026-03-03 14:11:55 +00:00
parent 6e92e40f1c
commit 1a5380e17e
33 changed files with 193 additions and 231 deletions

View File

@@ -1,33 +1,8 @@
name: Build and push container image
run-name: ${{ gitea.actor }} is building and pushing container image
name: Deploy website
run-name: ${{ gitea.actor }} is deploying update
on:
push:
branches:
- main
env:
GITEA_DOMAIN: git.alfieking.dev
GITEA_REGISTRY_USER: acetheking987
RESULT_IMAGE_NAME: acetheking987/alfieking.dev
jobs:
build-and-push-image:
runs-on: ubuntu-latest
container:
image: catthehacker/ubuntu:act-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to registry
uses: docker/login-action@v3
with:
registry: ${{ env.GITEA_DOMAIN }}
username: ${{ env.GITEA_REGISTRY_USER }}
password: ${{ secrets.CONTAINER_REGISTRY_TOKEN }}
- name: Build and push image
uses: docker/build-push-action@v6
with:
push: true
tags: ${{ env.GITEA_DOMAIN }}/${{ env.RESULT_IMAGE_NAME }}:latest

6
.gitignore vendored
View File

@@ -1,7 +1,3 @@
.venv
.env
flask_session
__pycache__
.vscode
db
app.log
.venv

View File

@@ -1,22 +0,0 @@
FROM python:alpine
# Set the working directory
WORKDIR /app
# Copy the requirements file into the container
COPY requirements.txt .
# Install the required packages
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install gunicorn
# Copy the rest of the application code into the container
COPY src src
COPY templates templates
COPY static static
# Expose the port the app runs on
EXPOSE 5000
# run the application
ENTRYPOINT [ "gunicorn", "-b", ":5000", "--access-logfile", "-", "--error-logfile", "-", "src.wsgi:app" ]

5
run.sh
View File

@@ -1,5 +0,0 @@
#!/bin/bash
[ ! -f .env ] || export $(grep -v '^#' .env | xargs)
flask --app src.wsgi.py --debug run

View File

@@ -1,22 +1,21 @@
# Imports
from flask import Blueprint, render_template, abort
from os import getenv as env
import logging, os, markdown
import os, markdown
# Create blueprint
bp = Blueprint(
'dynamic_routes',
__name__,
template_folder=env('TEMPLATE_FOLDER', default='templates'),
static_folder=env('STATIC_FOLDER', default='../static')
)
bp = Blueprint('dynamic_routes', __name__)
template_folder = "templates"
# helper func
def get_path(file) -> str:
return os.path.join(template_folder, "pages", file)
# Create logger
log = logging.getLogger(__name__)
# Get all files in folder
def ListFiles(path):
path = os.path.join(bp.template_folder, 'pages', path)
path = get_path(path)
files = []
for root, dirs, files_in_dir in os.walk(path):
for file in files_in_dir:
@@ -25,11 +24,12 @@ def ListFiles(path):
files.append(os.path.relpath(os.path.join(root, dir), path) + '/')
return files
# Catch-all route for generic pages
@bp.route('/<path:filename>')
def catch_all(filename):
if os.path.exists(os.path.join(bp.template_folder, 'pages', filename)):
if os.path.isdir(os.path.join(bp.template_folder, 'pages', filename)):
if os.path.exists(get_path(filename)):
if os.path.isdir(get_path(filename)):
return render_template(
'bases/directory.html',
directory=filename + "/" if not filename.endswith('/') else filename,
@@ -38,11 +38,11 @@ def catch_all(filename):
return render_template(f'pages/{filename}')
elif os.path.exists(os.path.join(bp.template_folder, 'pages', filename + '.html')):
elif os.path.exists(get_path(filename + '.html')):
return render_template(f'pages/{filename}.html')
elif os.path.exists(os.path.join(bp.template_folder, 'pages', filename + '.md')):
output = markdown.markdown(open(os.path.join(bp.template_folder, 'pages', filename + '.md'), "r").read())
elif os.path.exists(get_path(filename + '.md')):
output = markdown.markdown(open(get_path(filename + '.md'), "r").read())
return render_template(
f'bases/md.html',
title = filename.split("/")[-1],

39
src/errors.py Normal file
View File

@@ -0,0 +1,39 @@
from flask import Blueprint, render_template
from werkzeug.exceptions import HTTPException
from os import getenv as env
bp = Blueprint("errors", __name__)
@bp.route('/500')
@bp.app_errorhandler(500)
def internal_server_error(error:HTTPException=None):
return render_template('errors/500.html', error=error), 500
@bp.route('/404')
@bp.app_errorhandler(404)
def not_found(error:HTTPException=None):
return render_template('errors/404.html', error=error), 404
@bp.route('/400')
@bp.app_errorhandler(400)
def bad_request(error:HTTPException=None):
return render_template('errors/400.html', error=error), 400
@bp.route('/idk')
@bp.app_errorhandler(Exception)
def idk(error:HTTPException=None):
if not isinstance(error, HTTPException):
error = HTTPException("I honestly dont know")
error.code = 418
return render_template(
'errors/error.html',
code = error.code,
description = error.description,
name = error.name
), error.code

74
src/main.py Normal file
View File

@@ -0,0 +1,74 @@
# IMPORTS
from flask import Flask, render_template
from dotenv import load_dotenv
from os import getenv as env
import logging
try:
import src.dynamic_routes as dynamic_routes
import src.errors as errors
import src.pg_log as pg_log
except ImportError:
import dynamic_routes, errors, pg_log
# ENV
load_dotenv()
# LOGGING
pg_log_handler = pg_log.PgLog(
host = env("PG_HOST"),
port = env("PG_PORT"),
dbname = env("PG_DBNAME"),
user= env("PG_USER"),
password = env("PG_PASSWORD")
)
pg_log_handler.setLevel(logging.DEBUG)
stream_log_handler = logging.StreamHandler()
stream_log_handler.setFormatter(
logging.Formatter("%(asctime)s - %(levelname)s: %(message)s")
)
stream_log_handler.setLevel(logging.INFO)
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
log.addHandler(stream_log_handler)
log.addHandler(pg_log_handler)
werkzeug_logger = logging.getLogger("werkzeug")
werkzeug_logger.setLevel(logging.DEBUG)
werkzeug_logger.addHandler(pg_log_handler)
werkzeug_logger.addHandler(stream_log_handler)
log.info("Logging initialized.")
# CREATE FLASK APP
app = Flask(
__name__,
template_folder="../templates",
static_folder="../static"
)
# BLUEPRINTS
app.register_blueprint(errors.bp, url_prefix="/errors")
app.register_blueprint(dynamic_routes.bp, url_prefix="/")
# ROUTES
@app.route("/")
def index():
return render_template("index.html")
@app.route("/toaster")
def toaster():
return render_template("toaster.html")
# DEBUG (DONT RUN LIKE THIS IN PROD)
if __name__ == "__main__":
log.warning(f"RUNNING IN DEBUG MODE DO NOT USE FOR PRODUCTION!")
app.run(debug=True)

35
src/pg_log.py Normal file
View File

@@ -0,0 +1,35 @@
import psycopg2, logging
class PgLog(logging.StreamHandler):
def __init__(self, host, port, dbname, user, password):
super().__init__()
self.host = host
self.port = port
self.dbname = dbname
self.user = user
self.password = password
self.conn = psycopg2.connect(
database = dbname,
user = user,
password = password,
host = host,
port = port
)
self.cursor = self.conn.cursor()
def __del__(self):
self.cursor.close()
self.conn.close()
def emit(self, record):
self.cursor.execute(
f"INSERT INTO logs (level, message) VALUES (%s, %s)",
(
record.levelname,
record.getMessage(),
)
)
self.conn.commit()

View File

@@ -1,52 +0,0 @@
# Imports
from flask import Blueprint, render_template
from werkzeug.exceptions import HTTPException
from os import getenv as env
import logging
# Create blueprint
bp = Blueprint(
'error_handlers',
__name__,
template_folder=env('TEMPLATE_FOLDER', default='../templates'),
static_folder=env('STATIC_FOLDER', default='../static')
)
# Create logger
log = logging.getLogger(__name__)
# Route for 500 error
@bp.route('/500')
@bp.app_errorhandler(500)
def internal_server_error(error:HTTPException=None):
return render_template('errors/500.html', error=error), 500
# Route for 404 error
@bp.route('/404')
@bp.app_errorhandler(404)
def not_found(error:HTTPException=None):
return render_template('errors/404.html', error=error), 404
# Route for 400 error
@bp.route('/400')
@bp.app_errorhandler(400)
def bad_request(error:HTTPException=None):
return render_template('errors/400.html', error=error), 400
# Route for all other errors
@bp.route('/idk')
@bp.app_errorhandler(Exception)
def nah(error:HTTPException=None):
if isinstance(error, HTTPException):
return render_template(
'errors/error.html',
code = error.code,
description = error.description,
name = error.name
), error.code
return render_template(
'errors/error.html',
code=418,
description="I honestly dont know",
name="I'm a teapot"
), 418

View File

@@ -1,63 +0,0 @@
# Imports
from flask import Flask, render_template, send_file
from flask_session import Session
from dotenv import load_dotenv
from os import getenv as env
import logging
import src.routes.error_handlers
import src.routes.dynamic_routes
# Load env
load_dotenv()
# Create logger
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
stream_handler.setLevel(logging.INFO)
file_handler = logging.FileHandler(filename='app.log')
file_handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
file_handler.setLevel(logging.DEBUG)
# Add handlers to the logger
log = logging.getLogger()
log.setLevel(logging.DEBUG)
log.addHandler(stream_handler)
log.addHandler(file_handler)
log.info("Logging initialized")
# Create flask app
app = Flask(
__name__,
template_folder=env('TEMPLATE_FOLDER', default='../templates'),
static_folder=env('STATIC_FOLDER', default='../static')
)
# Configure sessions
app.config["SESSION_PERMANENT"] = True
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
# Load routes
app.register_blueprint(src.routes.error_handlers.bp, url_prefix='/error')
app.register_blueprint(src.routes.dynamic_routes.bp, url_prefix='/')
# Generic routes
@app.route('/')
def index():
return render_template('index.html')
@app.route('/favicon.ico')
def favicon():
return send_file('../static/content/other/favicon.ico')
@app.route('/robots.txt')
def robots():
return send_file('../static/content/other/robots.txt')
# Route for sitemap.xml
@app.route('/sitemap.xml')
def sitemap():
return send_file('../static/content/other/sitemap.xml')

View File

@@ -1,8 +1,6 @@
User-agent: *
Allow: /
Disallow: /404
Disallow: /500
Disallow: /400
Disallow: /errors
Sitemap: https://alfieking.dev/sitemap.xml

View File

@@ -6,13 +6,4 @@
<url>
<loc>https://alfieking.dev/toaster</loc>
</url>
<url>
<loc>https://alfieking.dev/events</loc>
</url>
<url>
<loc>https://alfieking.dev/events/paws-n-pistons</loc>
</url>
<url>
<loc>https://alfieking.dev/events/crittersmk</loc>
</url>
</urlset>

View File

@@ -41,7 +41,7 @@
</section>
</nav>
<section>
<h6 class="irken">heya, try typing "furry", "irken" or <span class="scratch">scratch</span> into this page!</h6>
<h6 class="irken">heya, try typing "furry", "irken" or "<span class="scratch">scratch</span>" into this page!</h6>
</section>
<section id="buttons">
<h1>BUTTONS</h1>

View File

@@ -37,18 +37,18 @@ protogen v1.0, toaster v1.0
<div class="gallery">
<h2 class="gallery-date">26th July 2025</h2>
<div class="gallery-images">
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_152110445.jpg" alt="Critters MK">
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_155134418.jpg" alt="Critters MK">
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_155226274.jpg" alt="Critters MK">
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_155434701.jpg" alt="Critters MK">
<img src="/static/content/photos/fur_meets/26-07-2025_critters_mk/PXL_20250726_152110445.jpg" alt="Critters MK">
<img src="/static/content/photos/fur_meets/26-07-2025_critters_mk/PXL_20250726_155134418.jpg" alt="Critters MK">
<img src="/static/content/photos/fur_meets/26-07-2025_critters_mk/PXL_20250726_155226274.jpg" alt="Critters MK">
<img src="/static/content/photos/fur_meets/26-07-2025_critters_mk/PXL_20250726_155434701.jpg" alt="Critters MK">
</div>
</div>
<div class="gallery">
<h2 class="gallery-date">23rd Aug 2025</h2>
<div class="gallery-images">
<img src="/static/content/fur_meets/23-08-2025_critters_mk/PXL_20250823_130640362.jpg" alt="Critters MK">
<img src="/static/content/fur_meets/23-08-2025_critters_mk/PXL_20250823_130648109.jpg" alt="Critters MK">
<img src="/static/content/fur_meets/23-08-2025_critters_mk/PXL_20250823_130659800.jpg" alt="Critters MK">
<img src="/static/content/photos/fur_meets/23-08-2025_critters_mk/PXL_20250823_130640362.jpg" alt="Critters MK">
<img src="/static/content/photos/fur_meets/23-08-2025_critters_mk/PXL_20250823_130648109.jpg" alt="Critters MK">
<img src="/static/content/photos/fur_meets/23-08-2025_critters_mk/PXL_20250823_130659800.jpg" alt="Critters MK">
</div>
</div>
</section>

View File

@@ -42,7 +42,7 @@ protogen v1.0, toaster v1.0
ALSO, one of them offered to let me try their fursuit!!! Im now going to speedrun going broke trying to get a fursuit of my own cus of this :3 (I was
already planning on getting one, but this just made me want one more).
<br>
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_200906329.jpg" alt="me in a fursuit" id="woooooo">
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_200906329.jpg" alt="me in a fursuit" id="woooooo">
<br>
The fursuit belongs to <a href="https://www.tiktok.com/@trickythefox" target="_blank">Tricky the Fox</a>, they are a very chill person and I had a great time talking to them ^w^.
<h1>Photos :3</h1>
@@ -52,14 +52,14 @@ protogen v1.0, toaster v1.0
<div class="gallery">
<h2 class="gallery-date">3rd Aug 2025</h2>
<div class="gallery-images">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_141943558.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150138054.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150249916.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_183614897.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_140629639.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_141242090.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_182023562.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_184321576.jpg" alt="Paws'N'Pistons">
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_141943558.jpg" alt="Paws'N'Pistons">
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150138054.jpg" alt="Paws'N'Pistons">
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150249916.jpg" alt="Paws'N'Pistons">
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_183614897.jpg" alt="Paws'N'Pistons">
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_140629639.jpg" alt="Paws'N'Pistons">
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_141242090.jpg" alt="Paws'N'Pistons">
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_182023562.jpg" alt="Paws'N'Pistons">
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_184321576.jpg" alt="Paws'N'Pistons">
</div>
</div>
</section>

View File

@@ -1,4 +0,0 @@
# hello
## this is a test
this is actually a md file, try putting .md at the end of this path

View File

@@ -86,19 +86,19 @@ protogen v1.0, toaster v1.0
<li>
<a href="/events/crittersmk"><b>Critters MK</b></a> - A furmeet in Milton Keynes.
<div class="fur-meet-gallery-small">
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_152110445.jpg" alt="Critters MK">
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_155134418.jpg" alt="Critters MK">
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_155226274.jpg" alt="Critters MK">
<img src="/static/content/fur_meets/26-07-2025_critters_mk/PXL_20250726_155434701.jpg" alt="Critters MK">
<img src="/static/content/photos/fur_meets/26-07-2025_critters_mk/PXL_20250726_152110445.jpg" alt="Critters MK">
<img src="/static/content/photos/fur_meets/26-07-2025_critters_mk/PXL_20250726_155134418.jpg" alt="Critters MK">
<img src="/static/content/photos/fur_meets/26-07-2025_critters_mk/PXL_20250726_155226274.jpg" alt="Critters MK">
<img src="/static/content/photos/fur_meets/26-07-2025_critters_mk/PXL_20250726_155434701.jpg" alt="Critters MK">
</div>
</li>
<li>
<a href="/events/paws-n-pistons"><b>Paws'N'Pistons</b></a> - A furry car meet around the UK.
<div class="fur-meet-gallery-small">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_141943558.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150138054.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150249916.jpg" alt="Paws'N'Pistons">
<img src="/static/content/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_183614897.jpg" alt="Paws'N'Pistons">
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_141943558.jpg" alt="Paws'N'Pistons">
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150138054.jpg" alt="Paws'N'Pistons">
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_150249916.jpg" alt="Paws'N'Pistons">
<img src="/static/content/photos/fur_meets/03-08-2025_paws_n_pistons/PXL_20250803_183614897.jpg" alt="Paws'N'Pistons">
</div>
</li>
<p>Click on the links to view more photos from each event :3</p>