feat: Split code into modules
All checks were successful
Build Docker / BuildImage (push) Successful in 4m7s
All checks were successful
Build Docker / BuildImage (push) Successful in 4m7s
This commit is contained in:
255
blueprints/api.py
Normal file
255
blueprints/api.py
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
from flask import Blueprint, request, jsonify, make_response
|
||||||
|
import os
|
||||||
|
import datetime
|
||||||
|
import requests
|
||||||
|
from mail import sendEmail
|
||||||
|
from sol import create_transaction, get_solana_address
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
api_bp = Blueprint('api', __name__)
|
||||||
|
|
||||||
|
ncReq = requests.get(
|
||||||
|
"https://cloud.woodburn.au/s/4ToXgFe3TnnFcN7/download/website-conf.json"
|
||||||
|
)
|
||||||
|
ncConfig = ncReq.json()
|
||||||
|
|
||||||
|
if 'time-zone' not in ncConfig:
|
||||||
|
ncConfig['time-zone'] = 10
|
||||||
|
|
||||||
|
|
||||||
|
def getClientIP(request):
|
||||||
|
x_forwarded_for = request.headers.get("X-Forwarded-For")
|
||||||
|
if x_forwarded_for:
|
||||||
|
ip = x_forwarded_for.split(",")[0]
|
||||||
|
else:
|
||||||
|
ip = request.remote_addr
|
||||||
|
return ip
|
||||||
|
|
||||||
|
def getGitCommit():
|
||||||
|
# if .git exists, get the latest commit hash
|
||||||
|
if os.path.isdir(".git"):
|
||||||
|
git_dir = ".git"
|
||||||
|
head_ref = ""
|
||||||
|
with open(os.path.join(git_dir, "HEAD")) as file:
|
||||||
|
head_ref = file.read().strip()
|
||||||
|
if head_ref.startswith("ref: "):
|
||||||
|
head_ref = head_ref[5:]
|
||||||
|
with open(os.path.join(git_dir, head_ref)) as file:
|
||||||
|
return file.read().strip()
|
||||||
|
else:
|
||||||
|
return head_ref
|
||||||
|
|
||||||
|
# Check if env SOURCE_COMMIT is set
|
||||||
|
if "SOURCE_COMMIT" in os.environ:
|
||||||
|
return os.environ["SOURCE_COMMIT"]
|
||||||
|
|
||||||
|
return "failed to get version"
|
||||||
|
|
||||||
|
@api_bp.route("/")
|
||||||
|
@api_bp.route("/help")
|
||||||
|
def api_help_get():
|
||||||
|
return jsonify({
|
||||||
|
"message": "Welcome to Nathan.Woodburn/ API! This is a personal website. For more information, visit https://nathan.woodburn.au",
|
||||||
|
"endpoints": {
|
||||||
|
"/time": "Get the current time",
|
||||||
|
"/timezone": "Get the current timezone",
|
||||||
|
"/message": "Get the message from the config",
|
||||||
|
"/ip": "Get your IP address",
|
||||||
|
"/project": "Get the current project from git",
|
||||||
|
"/version": "Get the current version of the website",
|
||||||
|
"/help": "Get this help message"
|
||||||
|
},
|
||||||
|
"version": getGitCommit()
|
||||||
|
})
|
||||||
|
|
||||||
|
@api_bp.route("/version")
|
||||||
|
def api_version_get():
|
||||||
|
return jsonify({"version": getGitCommit()})
|
||||||
|
|
||||||
|
@api_bp.route("/time")
|
||||||
|
def api_time_get():
|
||||||
|
timezone_offset = datetime.timedelta(hours=ncConfig["time-zone"])
|
||||||
|
timezone = datetime.timezone(offset=timezone_offset)
|
||||||
|
time = datetime.datetime.now(tz=timezone)
|
||||||
|
return jsonify({
|
||||||
|
"timestring": time.strftime("%A, %B %d, %Y %I:%M %p"),
|
||||||
|
"timestamp": time.timestamp(),
|
||||||
|
"timezone": ncConfig["time-zone"],
|
||||||
|
"timeISO": time.isoformat()
|
||||||
|
})
|
||||||
|
|
||||||
|
@api_bp.route("/timezone")
|
||||||
|
def api_timezone_get():
|
||||||
|
return jsonify({"timezone": ncConfig["time-zone"]})
|
||||||
|
|
||||||
|
@api_bp.route("/timezone", methods=["POST"])
|
||||||
|
def api_timezone_post():
|
||||||
|
# Refresh config
|
||||||
|
global ncConfig
|
||||||
|
conf = requests.get(
|
||||||
|
"https://cloud.woodburn.au/s/4ToXgFe3TnnFcN7/download/website-conf.json")
|
||||||
|
if conf.status_code != 200:
|
||||||
|
return jsonify({"message": "Error: Could not get timezone"})
|
||||||
|
if not conf.json():
|
||||||
|
return jsonify({"message": "Error: Could not get timezone"})
|
||||||
|
conf = conf.json()
|
||||||
|
if "time-zone" not in conf:
|
||||||
|
return jsonify({"message": "Error: Could not get timezone"})
|
||||||
|
|
||||||
|
ncConfig = conf
|
||||||
|
return jsonify({"message": "Successfully pulled latest timezone", "timezone": ncConfig["time-zone"]})
|
||||||
|
|
||||||
|
@api_bp.route("/message")
|
||||||
|
def api_message_get():
|
||||||
|
return jsonify({"message": ncConfig["message"]})
|
||||||
|
|
||||||
|
|
||||||
|
@api_bp.route("/ip")
|
||||||
|
def api_ip_get():
|
||||||
|
return jsonify({"ip": getClientIP(request)})
|
||||||
|
|
||||||
|
|
||||||
|
@api_bp.route("/email", methods=["POST"])
|
||||||
|
def api_email_post():
|
||||||
|
# Verify json
|
||||||
|
if not request.is_json:
|
||||||
|
return jsonify({
|
||||||
|
"status": 400,
|
||||||
|
"error": "Bad request JSON Data missing"
|
||||||
|
})
|
||||||
|
|
||||||
|
# Check if api key sent
|
||||||
|
data = request.json
|
||||||
|
if not data:
|
||||||
|
return jsonify({
|
||||||
|
"status": 400,
|
||||||
|
"error": "Bad request JSON Data missing"
|
||||||
|
})
|
||||||
|
|
||||||
|
if "key" not in data:
|
||||||
|
return jsonify({
|
||||||
|
"status": 401,
|
||||||
|
"error": "Unauthorized 'key' missing"
|
||||||
|
})
|
||||||
|
|
||||||
|
if data["key"] != os.getenv("EMAIL_KEY"):
|
||||||
|
return jsonify({
|
||||||
|
"status": 401,
|
||||||
|
"error": "Unauthorized 'key' invalid"
|
||||||
|
})
|
||||||
|
|
||||||
|
return sendEmail(data)
|
||||||
|
|
||||||
|
|
||||||
|
@api_bp.route("/project")
|
||||||
|
def api_project_get():
|
||||||
|
try:
|
||||||
|
git = requests.get(
|
||||||
|
"https://git.woodburn.au/users/nathanwoodburn/activities/feeds?only-performed-by=true&limit=1",
|
||||||
|
headers={"Authorization": os.getenv("git_token")},
|
||||||
|
)
|
||||||
|
git = git.json()
|
||||||
|
git = git[0]
|
||||||
|
repo_name = git["repo"]["name"]
|
||||||
|
repo_name = repo_name.lower()
|
||||||
|
repo_description = git["repo"]["description"]
|
||||||
|
except Exception as e:
|
||||||
|
repo_name = "nathanwoodburn.github.io"
|
||||||
|
repo_description = "Personal website"
|
||||||
|
git = {
|
||||||
|
"repo": {
|
||||||
|
"html_url": "https://nathan.woodburn.au",
|
||||||
|
"name": "nathanwoodburn.github.io",
|
||||||
|
"description": "Personal website",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print(f"Error getting git data: {e}")
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"repo_name": repo_name,
|
||||||
|
"repo_description": repo_description,
|
||||||
|
"git": git,
|
||||||
|
})
|
||||||
|
|
||||||
|
# region Solana Links
|
||||||
|
SOLANA_HEADERS = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-Action-Version": "2.4.2",
|
||||||
|
"X-Blockchain-Ids": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@api_bp.route("/donate", methods=["GET", "OPTIONS"])
|
||||||
|
def sol_donate_get():
|
||||||
|
data = {
|
||||||
|
"icon": "https://nathan.woodburn.au/assets/img/profile.png",
|
||||||
|
"label": "Donate to Nathan.Woodburn/",
|
||||||
|
"title": "Donate to Nathan.Woodburn/",
|
||||||
|
"description": "Student, developer, and crypto enthusiast",
|
||||||
|
"links": {
|
||||||
|
"actions": [
|
||||||
|
{"label": "0.01 SOL", "href": "/api/v1/donate/0.01"},
|
||||||
|
{"label": "0.1 SOL", "href": "/api/v1/donate/0.1"},
|
||||||
|
{"label": "1 SOL", "href": "/api/v1/donate/1"},
|
||||||
|
{
|
||||||
|
"href": "/api/v1/donate/{amount}",
|
||||||
|
"label": "Donate",
|
||||||
|
"parameters": [
|
||||||
|
{"name": "amount", "label": "Enter a custom SOL amount"}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
response = make_response(jsonify(data), 200, SOLANA_HEADERS)
|
||||||
|
|
||||||
|
if request.method == "OPTIONS":
|
||||||
|
response.headers["Access-Control-Allow-Origin"] = "*"
|
||||||
|
response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, OPTIONS"
|
||||||
|
response.headers["Access-Control-Allow-Headers"] = (
|
||||||
|
"Content-Type,Authorization,Content-Encoding,Accept-Encoding,X-Action-Version,X-Blockchain-Ids"
|
||||||
|
)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
@api_bp.route("/donate/<amount>")
|
||||||
|
def sol_donate_amount_get(amount):
|
||||||
|
data = {
|
||||||
|
"icon": "https://nathan.woodburn.au/assets/img/profile.png",
|
||||||
|
"label": f"Donate {amount} SOL to Nathan.Woodburn/",
|
||||||
|
"title": "Donate to Nathan.Woodburn/",
|
||||||
|
"description": f"Donate {amount} SOL to Nathan.Woodburn/",
|
||||||
|
}
|
||||||
|
return jsonify(data), 200, SOLANA_HEADERS
|
||||||
|
|
||||||
|
|
||||||
|
@api_bp.route("/donate/<amount>", methods=["POST"])
|
||||||
|
def sol_donate_post(amount):
|
||||||
|
|
||||||
|
if not request.json:
|
||||||
|
return jsonify({"message": "Error: No JSON data provided"}), 400, SOLANA_HEADERS
|
||||||
|
|
||||||
|
|
||||||
|
if "account" not in request.json:
|
||||||
|
return jsonify({"message": "Error: No account provided"}), 400, SOLANA_HEADERS
|
||||||
|
|
||||||
|
sender = request.json["account"]
|
||||||
|
|
||||||
|
# Make sure amount is a number
|
||||||
|
try:
|
||||||
|
amount = float(amount)
|
||||||
|
except ValueError:
|
||||||
|
amount = 1 # Default to 1 SOL if invalid
|
||||||
|
|
||||||
|
if amount < 0.0001:
|
||||||
|
return jsonify({"message": "Error: Amount too small"}), 400, SOLANA_HEADERS
|
||||||
|
|
||||||
|
transaction = create_transaction(sender, amount)
|
||||||
|
return jsonify({"message": "Success", "transaction": transaction}), 200, SOLANA_HEADERS
|
||||||
|
|
||||||
|
# endregion
|
||||||
|
|
||||||
@@ -1,14 +1,17 @@
|
|||||||
import os
|
import os
|
||||||
from flask import render_template
|
from flask import Blueprint, render_template, request
|
||||||
import markdown
|
import markdown
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
blog_bp = Blueprint('blog', __name__)
|
||||||
|
|
||||||
|
|
||||||
def list_blog_page_files():
|
def list_blog_page_files():
|
||||||
blog_pages = os.listdir("data/blog")
|
blog_pages = os.listdir("data/blog")
|
||||||
# Remove .md extension
|
# Remove .md extension
|
||||||
blog_pages = [page.removesuffix(".md") for page in blog_pages if page.endswith(".md")]
|
blog_pages = [page.removesuffix(".md")
|
||||||
|
for page in blog_pages if page.endswith(".md")]
|
||||||
|
|
||||||
return blog_pages
|
return blog_pages
|
||||||
|
|
||||||
@@ -23,12 +26,12 @@ def render_blog_page(date,handshake_scripts=None):
|
|||||||
# Get the title from the file name
|
# Get the title from the file name
|
||||||
title = date.removesuffix(".md").replace("_", " ")
|
title = date.removesuffix(".md").replace("_", " ")
|
||||||
# Convert the md to html
|
# Convert the md to html
|
||||||
content = markdown.markdown(content, extensions=['sane_lists', 'codehilite', 'fenced_code'])
|
content = markdown.markdown(
|
||||||
|
content, extensions=['sane_lists', 'codehilite', 'fenced_code'])
|
||||||
# Add target="_blank" to all links
|
# Add target="_blank" to all links
|
||||||
content = content.replace('<a href="', '<a target="_blank" href="')
|
content = content.replace('<a href="', '<a target="_blank" href="')
|
||||||
|
|
||||||
content = content.replace("<h4", "<h4 style='margin-bottom:0px;'")
|
content = content.replace("<h4", "<h4 style='margin-bottom:0px;'")
|
||||||
|
|
||||||
content = fix_numbered_lists(content)
|
content = fix_numbered_lists(content)
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
@@ -62,7 +65,8 @@ def fix_numbered_lists(html):
|
|||||||
for i in range(0, len(steps), 2):
|
for i in range(0, len(steps), 2):
|
||||||
if i+1 < len(steps):
|
if i+1 < len(steps):
|
||||||
step_html = steps[i+1].strip()
|
step_html = steps[i+1].strip()
|
||||||
ol_items.append(f"<li style='list-style: auto;'>{step_html}</li>")
|
ol_items.append(
|
||||||
|
f"<li style='list-style: auto;'>{step_html}</li>")
|
||||||
|
|
||||||
# Build the final list HTML
|
# Build the final list HTML
|
||||||
ol_html = "<ol>\n" + "\n".join(ol_items) + "\n</ol>"
|
ol_html = "<ol>\n" + "\n".join(ol_items) + "\n</ol>"
|
||||||
@@ -97,3 +101,34 @@ def render_blog_home(handshake_scripts=None):
|
|||||||
blogs=blog_pages,
|
blogs=blog_pages,
|
||||||
handshake_scripts=handshake_scripts,
|
handshake_scripts=handshake_scripts,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@blog_bp.route("/")
|
||||||
|
def blog_index_get():
|
||||||
|
global handshake_scripts
|
||||||
|
|
||||||
|
# If localhost, don't load handshake
|
||||||
|
if (
|
||||||
|
request.host == "localhost:5000"
|
||||||
|
or request.host == "127.0.0.1:5000"
|
||||||
|
or os.getenv("dev") == "true"
|
||||||
|
or request.host == "test.nathan.woodburn.au"
|
||||||
|
):
|
||||||
|
handshake_scripts = ""
|
||||||
|
|
||||||
|
return render_blog_home(handshake_scripts)
|
||||||
|
|
||||||
|
|
||||||
|
@blog_bp.route("/<path:path>")
|
||||||
|
def blog_path_get(path):
|
||||||
|
global handshake_scripts
|
||||||
|
# If localhost, don't load handshake
|
||||||
|
if (
|
||||||
|
request.host == "localhost:5000"
|
||||||
|
or request.host == "127.0.0.1:5000"
|
||||||
|
or os.getenv("dev") == "true"
|
||||||
|
or request.host == "test.nathan.woodburn.au"
|
||||||
|
):
|
||||||
|
handshake_scripts = ""
|
||||||
|
|
||||||
|
return render_blog_page(path, handshake_scripts)
|
||||||
140
blueprints/now.py
Normal file
140
blueprints/now.py
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
from flask import Blueprint, render_template, make_response, request, jsonify
|
||||||
|
import datetime
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Create blueprint
|
||||||
|
now_bp = Blueprint('now', __name__)
|
||||||
|
|
||||||
|
def list_now_page_files():
|
||||||
|
now_pages = os.listdir("templates/now")
|
||||||
|
now_pages = [
|
||||||
|
page for page in now_pages if page != "template.html" and page != "old.html"
|
||||||
|
]
|
||||||
|
now_pages.sort(reverse=True)
|
||||||
|
return now_pages
|
||||||
|
|
||||||
|
def list_now_dates():
|
||||||
|
now_pages = list_now_page_files()
|
||||||
|
now_dates = [page.split(".")[0] for page in now_pages]
|
||||||
|
return now_dates
|
||||||
|
|
||||||
|
def get_latest_now_date(formatted=False):
|
||||||
|
if formatted:
|
||||||
|
date=list_now_dates()[0]
|
||||||
|
date = datetime.datetime.strptime(date, "%y_%m_%d")
|
||||||
|
date = date.strftime("%A, %B %d, %Y")
|
||||||
|
return date
|
||||||
|
return list_now_dates()[0]
|
||||||
|
|
||||||
|
def render_latest_now(handshake_scripts=None):
|
||||||
|
now_page = list_now_dates()[0]
|
||||||
|
return render_now_page(now_page,handshake_scripts=handshake_scripts)
|
||||||
|
|
||||||
|
def render_now_page(date,handshake_scripts=None):
|
||||||
|
# If the date is not available, render the latest page
|
||||||
|
if date is None:
|
||||||
|
return render_latest_now(handshake_scripts=handshake_scripts)
|
||||||
|
# Remove .html
|
||||||
|
date = date.removesuffix(".html")
|
||||||
|
|
||||||
|
if date not in list_now_dates():
|
||||||
|
return render_template("404.html"), 404
|
||||||
|
|
||||||
|
|
||||||
|
date_formatted = datetime.datetime.strptime(date, "%y_%m_%d")
|
||||||
|
date_formatted = date_formatted.strftime("%A, %B %d, %Y")
|
||||||
|
return render_template(f"now/{date}.html",DATE=date_formatted,handshake_scripts=handshake_scripts)
|
||||||
|
|
||||||
|
@now_bp.route("/")
|
||||||
|
def now_index_get():
|
||||||
|
handshake_scripts = ''
|
||||||
|
# If localhost, don't load handshake
|
||||||
|
if (
|
||||||
|
request.host == "localhost:5000"
|
||||||
|
or request.host == "127.0.0.1:5000"
|
||||||
|
or os.getenv("dev") == "true"
|
||||||
|
or request.host == "test.nathan.woodburn.au"
|
||||||
|
):
|
||||||
|
handshake_scripts = ""
|
||||||
|
else:
|
||||||
|
handshake_scripts = '<script src="https://nathan.woodburn/handshake.js" domain="nathan.woodburn" async></script><script src="https://nathan.woodburn/https.js" async></script>'
|
||||||
|
|
||||||
|
return render_latest_now(handshake_scripts)
|
||||||
|
|
||||||
|
|
||||||
|
@now_bp.route("/<path:path>")
|
||||||
|
def now_path_get(path):
|
||||||
|
handshake_scripts = ''
|
||||||
|
# If localhost, don't load handshake
|
||||||
|
if (
|
||||||
|
request.host == "localhost:5000"
|
||||||
|
or request.host == "127.0.0.1:5000"
|
||||||
|
or os.getenv("dev") == "true"
|
||||||
|
or request.host == "test.nathan.woodburn.au"
|
||||||
|
):
|
||||||
|
handshake_scripts = ""
|
||||||
|
else:
|
||||||
|
handshake_scripts = '<script src="https://nathan.woodburn/handshake.js" domain="nathan.woodburn" async></script><script src="https://nathan.woodburn/https.js" async></script>'
|
||||||
|
|
||||||
|
return render_now_page(path, handshake_scripts)
|
||||||
|
|
||||||
|
|
||||||
|
@now_bp.route("/old")
|
||||||
|
@now_bp.route("/old/")
|
||||||
|
def now_old_get():
|
||||||
|
handshake_scripts = ''
|
||||||
|
# If localhost, don't load handshake
|
||||||
|
if (
|
||||||
|
request.host == "localhost:5000"
|
||||||
|
or request.host == "127.0.0.1:5000"
|
||||||
|
or os.getenv("dev") == "true"
|
||||||
|
or request.host == "test.nathan.woodburn.au"
|
||||||
|
):
|
||||||
|
handshake_scripts = ""
|
||||||
|
else:
|
||||||
|
handshake_scripts = '<script src="https://nathan.woodburn/handshake.js" domain="nathan.woodburn" async></script><script src="https://nathan.woodburn/https.js" async></script>'
|
||||||
|
|
||||||
|
now_dates = list_now_dates()[1:]
|
||||||
|
html = '<ul class="list-group">'
|
||||||
|
html += f'<a style="text-decoration:none;" href="/now"><li class="list-group-item" style="background-color:#000000;color:#ffffff;">{get_latest_now_date(True)}</li></a>'
|
||||||
|
|
||||||
|
for date in now_dates:
|
||||||
|
link = date
|
||||||
|
date = datetime.datetime.strptime(date, "%y_%m_%d")
|
||||||
|
date = date.strftime("%A, %B %d, %Y")
|
||||||
|
html += f'<a style="text-decoration:none;" href="/now/{link}"><li class="list-group-item" style="background-color:#000000;color:#ffffff;">{date}</li></a>'
|
||||||
|
|
||||||
|
html += "</ul>"
|
||||||
|
return render_template(
|
||||||
|
"now/old.html", handshake_scripts=handshake_scripts, now_pages=html
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@now_bp.route("/now.rss")
|
||||||
|
@now_bp.route("/now.xml")
|
||||||
|
@now_bp.route("/rss.xml")
|
||||||
|
def now_rss_get():
|
||||||
|
host = "https://" + request.host
|
||||||
|
if ":" in request.host:
|
||||||
|
host = "http://" + request.host
|
||||||
|
# Generate RSS feed
|
||||||
|
now_pages = list_now_page_files()
|
||||||
|
rss = f'<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Nathan.Woodburn/</title><link>{host}</link><description>See what I\'ve been up to</description><language>en-us</language><lastBuildDate>{datetime.datetime.now(tz=datetime.timezone.utc).strftime("%a, %d %b %Y %H:%M:%S %z")}</lastBuildDate><atom:link href="{host}/now.rss" rel="self" type="application/rss+xml" />'
|
||||||
|
for page in now_pages:
|
||||||
|
link = page.strip(".html")
|
||||||
|
date = datetime.datetime.strptime(link, "%y_%m_%d")
|
||||||
|
date = date.strftime("%A, %B %d, %Y")
|
||||||
|
rss += f'<item><title>What\'s Happening {date}</title><link>{host}/now/{link}</link><description>Latest updates for {date}</description><guid>{host}/now/{link}</guid></item>'
|
||||||
|
rss += "</channel></rss>"
|
||||||
|
return make_response(rss, 200, {"Content-Type": "application/rss+xml"})
|
||||||
|
|
||||||
|
|
||||||
|
@now_bp.route("/now.json")
|
||||||
|
def now_json_get():
|
||||||
|
now_pages = list_now_page_files()
|
||||||
|
host = "https://" + request.host
|
||||||
|
if ":" in request.host:
|
||||||
|
host = "http://" + request.host
|
||||||
|
now_pages = [{"url": host+"/now/"+page.strip(".html"), "date": datetime.datetime.strptime(page.strip(".html"), "%y_%m_%d").strftime(
|
||||||
|
"%A, %B %d, %Y"), "title": "What's Happening "+datetime.datetime.strptime(page.strip(".html"), "%y_%m_%d").strftime("%A, %B %d, %Y")} for page in now_pages]
|
||||||
|
return jsonify(now_pages)
|
||||||
62
blueprints/wellknown.py
Normal file
62
blueprints/wellknown.py
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
from flask import Blueprint, render_template, make_response, request, jsonify, send_from_directory, redirect
|
||||||
|
import os
|
||||||
|
|
||||||
|
wk_bp = Blueprint('well-known', __name__)
|
||||||
|
|
||||||
|
|
||||||
|
@wk_bp.route("/<path:path>")
|
||||||
|
def wk_index_get(path):
|
||||||
|
return send_from_directory(".well-known", path)
|
||||||
|
|
||||||
|
|
||||||
|
@wk_bp.route("/wallets/<path:path>")
|
||||||
|
def wk_wallet_get(path):
|
||||||
|
if path[0] == "." and 'proof' not in path:
|
||||||
|
return send_from_directory(
|
||||||
|
".well-known/wallets", path, mimetype="application/json"
|
||||||
|
)
|
||||||
|
elif os.path.isfile(".well-known/wallets/" + path):
|
||||||
|
address = ""
|
||||||
|
with open(".well-known/wallets/" + path) as file:
|
||||||
|
address = file.read()
|
||||||
|
address = address.strip()
|
||||||
|
return make_response(address, 200, {"Content-Type": "text/plain"})
|
||||||
|
|
||||||
|
if os.path.isfile(".well-known/wallets/" + path.upper()):
|
||||||
|
return redirect("/.well-known/wallets/" + path.upper(), code=302)
|
||||||
|
|
||||||
|
return render_template("404.html"), 404
|
||||||
|
|
||||||
|
|
||||||
|
@wk_bp.route("/nostr.json")
|
||||||
|
def wk_nostr_get():
|
||||||
|
# Get name parameter
|
||||||
|
name = request.args.get("name")
|
||||||
|
if name:
|
||||||
|
return jsonify(
|
||||||
|
{
|
||||||
|
"names": {
|
||||||
|
name: "b57b6a06fdf0a4095eba69eee26e2bf6fa72bd1ce6cbe9a6f72a7021c7acaa82"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return jsonify(
|
||||||
|
{
|
||||||
|
"names": {
|
||||||
|
"nathan": "b57b6a06fdf0a4095eba69eee26e2bf6fa72bd1ce6cbe9a6f72a7021c7acaa82",
|
||||||
|
"_": "b57b6a06fdf0a4095eba69eee26e2bf6fa72bd1ce6cbe9a6f72a7021c7acaa82",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@wk_bp.route("/xrp-ledger.toml")
|
||||||
|
def wk_xrp_get():
|
||||||
|
# Create a response with the xrp-ledger.toml file
|
||||||
|
with open(".well-known/xrp-ledger.toml") as file:
|
||||||
|
toml = file.read()
|
||||||
|
|
||||||
|
response = make_response(toml, 200, {"Content-Type": "application/toml"})
|
||||||
|
# Set cors headers
|
||||||
|
response.headers["Access-Control-Allow-Origin"] = "*"
|
||||||
|
return response
|
||||||
43
now.py
43
now.py
@@ -1,43 +0,0 @@
|
|||||||
import os
|
|
||||||
from flask import render_template
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
def list_now_page_files():
|
|
||||||
now_pages = os.listdir("templates/now")
|
|
||||||
now_pages = [
|
|
||||||
page for page in now_pages if page != "template.html" and page != "old.html"
|
|
||||||
]
|
|
||||||
now_pages.sort(reverse=True)
|
|
||||||
return now_pages
|
|
||||||
|
|
||||||
def list_now_dates():
|
|
||||||
now_pages = list_now_page_files()
|
|
||||||
now_dates = [page.split(".")[0] for page in now_pages]
|
|
||||||
return now_dates
|
|
||||||
|
|
||||||
def get_latest_now_date(formatted=False):
|
|
||||||
if formatted:
|
|
||||||
date=list_now_dates()[0]
|
|
||||||
date = datetime.strptime(date, "%y_%m_%d")
|
|
||||||
date = date.strftime("%A, %B %d, %Y")
|
|
||||||
return date
|
|
||||||
return list_now_dates()[0]
|
|
||||||
|
|
||||||
def render_now_page(date,handshake_scripts=None):
|
|
||||||
# If the date is not available, render the latest page
|
|
||||||
if date is None:
|
|
||||||
return render_latest_now(handshake_scripts=handshake_scripts)
|
|
||||||
# Remove .html
|
|
||||||
date = date.removesuffix(".html")
|
|
||||||
|
|
||||||
if date not in list_now_dates():
|
|
||||||
return render_template("404.html"), 404
|
|
||||||
|
|
||||||
|
|
||||||
date_formatted = datetime.strptime(date, "%y_%m_%d")
|
|
||||||
date_formatted = date_formatted.strftime("%A, %B %d, %Y")
|
|
||||||
return render_template(f"now/{date}.html",DATE=date_formatted,handshake_scripts=handshake_scripts)
|
|
||||||
|
|
||||||
def render_latest_now(handshake_scripts=None):
|
|
||||||
now_page = list_now_dates()[0]
|
|
||||||
return render_now_page(now_page,handshake_scripts=handshake_scripts)
|
|
||||||
483
server.py
483
server.py
@@ -20,20 +20,21 @@ from qrcode.constants import ERROR_CORRECT_L, ERROR_CORRECT_H
|
|||||||
from ansi2html import Ansi2HTMLConverter
|
from ansi2html import Ansi2HTMLConverter
|
||||||
from functools import cache
|
from functools import cache
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from mail import sendEmail
|
from blueprints.now import now_bp
|
||||||
from now import (
|
from blueprints.blog import blog_bp
|
||||||
list_now_dates,
|
from blueprints.wellknown import wk_bp
|
||||||
get_latest_now_date,
|
from blueprints.api import api_bp, getGitCommit, getClientIP
|
||||||
list_now_page_files,
|
|
||||||
render_latest_now,
|
|
||||||
render_now_page,
|
|
||||||
)
|
|
||||||
from blog import render_blog_home, render_blog_page
|
|
||||||
from sol import create_transaction
|
from sol import create_transaction
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
CORS(app)
|
CORS(app)
|
||||||
|
|
||||||
|
# Register the now blueprint with the URL prefix
|
||||||
|
app.register_blueprint(now_bp, url_prefix='/now')
|
||||||
|
app.register_blueprint(blog_bp, url_prefix='/blog')
|
||||||
|
app.register_blueprint(wk_bp, url_prefix='/.well-known')
|
||||||
|
app.register_blueprint(api_bp, url_prefix='/api/v1')
|
||||||
|
|
||||||
dotenv.load_dotenv()
|
dotenv.load_dotenv()
|
||||||
|
|
||||||
# Rate limiting for hosting enquiries
|
# Rate limiting for hosting enquiries
|
||||||
@@ -93,35 +94,6 @@ def getFilePath(name, path):
|
|||||||
return os.path.join(root, name)
|
return os.path.join(root, name)
|
||||||
|
|
||||||
|
|
||||||
def getClientIP(request):
|
|
||||||
x_forwarded_for = request.headers.get("X-Forwarded-For")
|
|
||||||
if x_forwarded_for:
|
|
||||||
ip = x_forwarded_for.split(",")[0]
|
|
||||||
else:
|
|
||||||
ip = request.remote_addr
|
|
||||||
return ip
|
|
||||||
|
|
||||||
|
|
||||||
def getGitCommit():
|
|
||||||
# if .git exists, get the latest commit hash
|
|
||||||
if os.path.isdir(".git"):
|
|
||||||
git_dir = ".git"
|
|
||||||
head_ref = ""
|
|
||||||
with open(os.path.join(git_dir, "HEAD")) as file:
|
|
||||||
head_ref = file.read().strip()
|
|
||||||
if head_ref.startswith("ref: "):
|
|
||||||
head_ref = head_ref[5:]
|
|
||||||
with open(os.path.join(git_dir, head_ref)) as file:
|
|
||||||
return file.read().strip()
|
|
||||||
else:
|
|
||||||
return head_ref
|
|
||||||
|
|
||||||
# Check if env SOURCE_COMMIT is set
|
|
||||||
if "SOURCE_COMMIT" in os.environ:
|
|
||||||
return os.environ["SOURCE_COMMIT"]
|
|
||||||
|
|
||||||
return "failed to get version"
|
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|
||||||
|
|
||||||
@@ -190,68 +162,6 @@ def javascript_get(name):
|
|||||||
return render_template("404.html"), 404
|
return render_template("404.html"), 404
|
||||||
return send_from_directory("templates/assets/js", request.path.split("/")[-1])
|
return send_from_directory("templates/assets/js", request.path.split("/")[-1])
|
||||||
|
|
||||||
# endregion
|
|
||||||
|
|
||||||
# region Well-known routes
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/.well-known/<path:path>")
|
|
||||||
def wk_index_get(path):
|
|
||||||
return send_from_directory(".well-known", path)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/.well-known/wallets/<path:path>")
|
|
||||||
def wk_wallet_get(path):
|
|
||||||
if path[0] == "." and 'proof' not in path:
|
|
||||||
return send_from_directory(
|
|
||||||
".well-known/wallets", path, mimetype="application/json"
|
|
||||||
)
|
|
||||||
elif os.path.isfile(".well-known/wallets/" + path):
|
|
||||||
address = ""
|
|
||||||
with open(".well-known/wallets/" + path) as file:
|
|
||||||
address = file.read()
|
|
||||||
address = address.strip()
|
|
||||||
return make_response(address, 200, {"Content-Type": "text/plain"})
|
|
||||||
|
|
||||||
if os.path.isfile(".well-known/wallets/" + path.upper()):
|
|
||||||
return redirect("/.well-known/wallets/" + path.upper(), code=302)
|
|
||||||
|
|
||||||
return render_template("404.html"), 404
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/.well-known/nostr.json")
|
|
||||||
def wk_nostr_get():
|
|
||||||
# Get name parameter
|
|
||||||
name = request.args.get("name")
|
|
||||||
if name:
|
|
||||||
return jsonify(
|
|
||||||
{
|
|
||||||
"names": {
|
|
||||||
name: "b57b6a06fdf0a4095eba69eee26e2bf6fa72bd1ce6cbe9a6f72a7021c7acaa82"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return jsonify(
|
|
||||||
{
|
|
||||||
"names": {
|
|
||||||
"nathan": "b57b6a06fdf0a4095eba69eee26e2bf6fa72bd1ce6cbe9a6f72a7021c7acaa82",
|
|
||||||
"_": "b57b6a06fdf0a4095eba69eee26e2bf6fa72bd1ce6cbe9a6f72a7021c7acaa82",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/.well-known/xrp-ledger.toml")
|
|
||||||
def wk_xrp_get():
|
|
||||||
# Create a response with the xrp-ledger.toml file
|
|
||||||
with open(".well-known/xrp-ledger.toml") as file:
|
|
||||||
toml = file.read()
|
|
||||||
|
|
||||||
response = make_response(toml, 200, {"Content-Type": "application/toml"})
|
|
||||||
# Set cors headers
|
|
||||||
response.headers["Access-Control-Allow-Origin"] = "*"
|
|
||||||
return response
|
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
# region PWA routes
|
# region PWA routes
|
||||||
|
|
||||||
@@ -279,236 +189,6 @@ def serviceWorker_get():
|
|||||||
# endregion
|
# endregion
|
||||||
|
|
||||||
|
|
||||||
# region Solana Links
|
|
||||||
SOLANA_HEADERS = {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Action-Version": "2.4.2",
|
|
||||||
"X-Blockchain-Ids": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/actions.json")
|
|
||||||
def sol_actions_get():
|
|
||||||
return jsonify(
|
|
||||||
{"rules": [{"pathPattern": "/donate**", "apiPath": "/api/donate**"}]}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/donate", methods=["GET", "OPTIONS"])
|
|
||||||
def sol_donate_get():
|
|
||||||
data = {
|
|
||||||
"icon": "https://nathan.woodburn.au/assets/img/profile.png",
|
|
||||||
"label": "Donate to Nathan.Woodburn/",
|
|
||||||
"title": "Donate to Nathan.Woodburn/",
|
|
||||||
"description": "Student, developer, and crypto enthusiast",
|
|
||||||
"links": {
|
|
||||||
"actions": [
|
|
||||||
{"label": "0.01 SOL", "href": "/api/donate/0.01"},
|
|
||||||
{"label": "0.1 SOL", "href": "/api/donate/0.1"},
|
|
||||||
{"label": "1 SOL", "href": "/api/donate/1"},
|
|
||||||
{
|
|
||||||
"href": "/api/donate/{amount}",
|
|
||||||
"label": "Donate",
|
|
||||||
"parameters": [
|
|
||||||
{"name": "amount", "label": "Enter a custom SOL amount"}
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
response = make_response(jsonify(data), 200, SOLANA_HEADERS)
|
|
||||||
|
|
||||||
if request.method == "OPTIONS":
|
|
||||||
response.headers["Access-Control-Allow-Origin"] = "*"
|
|
||||||
response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, OPTIONS"
|
|
||||||
response.headers["Access-Control-Allow-Headers"] = (
|
|
||||||
"Content-Type,Authorization,Content-Encoding,Accept-Encoding,X-Action-Version,X-Blockchain-Ids"
|
|
||||||
)
|
|
||||||
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/donate/<amount>")
|
|
||||||
def sol_donate_amount_get(amount):
|
|
||||||
data = {
|
|
||||||
"icon": "https://nathan.woodburn.au/assets/img/profile.png",
|
|
||||||
"label": f"Donate {amount} SOL to Nathan.Woodburn/",
|
|
||||||
"title": "Donate to Nathan.Woodburn/",
|
|
||||||
"description": f"Donate {amount} SOL to Nathan.Woodburn/",
|
|
||||||
}
|
|
||||||
return jsonify(data), 200, SOLANA_HEADERS
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/donate/<amount>", methods=["POST"])
|
|
||||||
def sol_donate_post(amount):
|
|
||||||
if not request.json:
|
|
||||||
return jsonify({"message": "Error: No JSON data provided"}), 400, SOLANA_HEADERS
|
|
||||||
|
|
||||||
if "account" not in request.json:
|
|
||||||
return jsonify({"message": "Error: No account provided"}), 400, SOLANA_HEADERS
|
|
||||||
|
|
||||||
sender = request.json["account"]
|
|
||||||
|
|
||||||
# Make sure amount is a number
|
|
||||||
try:
|
|
||||||
amount = float(amount)
|
|
||||||
except ValueError:
|
|
||||||
return jsonify({"message": "Error: Invalid amount"}), 400, SOLANA_HEADERS
|
|
||||||
|
|
||||||
if amount < 0.0001:
|
|
||||||
return jsonify({"message": "Error: Amount too small"}), 400, SOLANA_HEADERS
|
|
||||||
|
|
||||||
transaction = create_transaction(sender, amount)
|
|
||||||
return jsonify({"message": "Success", "transaction": transaction}), 200, SOLANA_HEADERS
|
|
||||||
|
|
||||||
# endregion
|
|
||||||
|
|
||||||
# region API routes
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/version")
|
|
||||||
@app.route("/api/v1/version")
|
|
||||||
def api_version_get():
|
|
||||||
return jsonify({"version": getGitCommit()})
|
|
||||||
|
|
||||||
@app.route("/api")
|
|
||||||
@app.route("/api/")
|
|
||||||
@app.route("/api/v1")
|
|
||||||
@app.route("/api/v1/")
|
|
||||||
@app.route("/api/help")
|
|
||||||
def api_help_get():
|
|
||||||
return jsonify({
|
|
||||||
"message": "Welcome to Nathan.Woodburn/ API! This is a personal website. For more information, visit https://nathan.woodburn.au",
|
|
||||||
"endpoints": {
|
|
||||||
"/api/v1/time": "Get the current time",
|
|
||||||
"/api/v1/timezone": "Get the current timezone",
|
|
||||||
"/api/v1/message": "Get the message from the config",
|
|
||||||
"/api/v1/ip": "Get your IP address",
|
|
||||||
"/api/v1/project": "Get the current project from git",
|
|
||||||
"/api/v1/version": "Get the current version of the website",
|
|
||||||
"/api/v1/help": "Get this help message"
|
|
||||||
},
|
|
||||||
"version": getGitCommit()
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/time")
|
|
||||||
@app.route("/api/v1/time")
|
|
||||||
def api_time_get():
|
|
||||||
timezone_offset = datetime.timedelta(hours=ncConfig["time-zone"])
|
|
||||||
timezone = datetime.timezone(offset=timezone_offset)
|
|
||||||
time = datetime.datetime.now(tz=timezone)
|
|
||||||
return jsonify({
|
|
||||||
"timestring": time.strftime("%A, %B %d, %Y %I:%M %p"),
|
|
||||||
"timestamp": time.timestamp(),
|
|
||||||
"timezone": ncConfig["time-zone"],
|
|
||||||
"timeISO": time.isoformat()
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/timezone")
|
|
||||||
@app.route("/api/v1/timezone")
|
|
||||||
def api_timezone_get():
|
|
||||||
return jsonify({"timezone": ncConfig["time-zone"]})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/timezone", methods=["POST"])
|
|
||||||
@app.route("/api/v1/timezone", methods=["POST"])
|
|
||||||
def api_timezone_post():
|
|
||||||
# Refresh config
|
|
||||||
global ncConfig
|
|
||||||
conf = requests.get(
|
|
||||||
"https://cloud.woodburn.au/s/4ToXgFe3TnnFcN7/download/website-conf.json")
|
|
||||||
if conf.status_code != 200:
|
|
||||||
return jsonify({"message": "Error: Could not get timezone"})
|
|
||||||
if not conf.json():
|
|
||||||
return jsonify({"message": "Error: Could not get timezone"})
|
|
||||||
conf = conf.json()
|
|
||||||
if "time-zone" not in conf:
|
|
||||||
return jsonify({"message": "Error: Could not get timezone"})
|
|
||||||
|
|
||||||
ncConfig = conf
|
|
||||||
return jsonify({"message": "Successfully pulled latest timezone", "timezone": ncConfig["time-zone"]})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/message")
|
|
||||||
@app.route("/api/v1/message")
|
|
||||||
def api_message_get():
|
|
||||||
return jsonify({"message": ncConfig["message"]})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/ip")
|
|
||||||
@app.route("/api/v1/ip")
|
|
||||||
def api_ip_get():
|
|
||||||
return jsonify({"ip": getClientIP(request)})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/email", methods=["POST"])
|
|
||||||
@app.route("/api/v1/email", methods=["POST"])
|
|
||||||
def api_email_post():
|
|
||||||
# Verify json
|
|
||||||
if not request.is_json:
|
|
||||||
return jsonify({
|
|
||||||
"status": 400,
|
|
||||||
"error": "Bad request JSON Data missing"
|
|
||||||
})
|
|
||||||
|
|
||||||
# Check if api key sent
|
|
||||||
data = request.json
|
|
||||||
if not data:
|
|
||||||
return jsonify({
|
|
||||||
"status": 400,
|
|
||||||
"error": "Bad request JSON Data missing"
|
|
||||||
})
|
|
||||||
|
|
||||||
if "key" not in data:
|
|
||||||
return jsonify({
|
|
||||||
"status": 401,
|
|
||||||
"error": "Unauthorized 'key' missing"
|
|
||||||
})
|
|
||||||
|
|
||||||
if data["key"] != os.getenv("EMAIL_KEY"):
|
|
||||||
return jsonify({
|
|
||||||
"status": 401,
|
|
||||||
"error": "Unauthorized 'key' invalid"
|
|
||||||
})
|
|
||||||
|
|
||||||
return sendEmail(data)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/v1/project")
|
|
||||||
def api_project_get():
|
|
||||||
try:
|
|
||||||
git = requests.get(
|
|
||||||
"https://git.woodburn.au/api/v1/users/nathanwoodburn/activities/feeds?only-performed-by=true&limit=1",
|
|
||||||
headers={"Authorization": os.getenv("git_token")},
|
|
||||||
)
|
|
||||||
git = git.json()
|
|
||||||
git = git[0]
|
|
||||||
repo_name = git["repo"]["name"]
|
|
||||||
repo_name = repo_name.lower()
|
|
||||||
repo_description = git["repo"]["description"]
|
|
||||||
except Exception as e:
|
|
||||||
repo_name = "nathanwoodburn.github.io"
|
|
||||||
repo_description = "Personal website"
|
|
||||||
git = {
|
|
||||||
"repo": {
|
|
||||||
"html_url": "https://nathan.woodburn.au",
|
|
||||||
"name": "nathanwoodburn.github.io",
|
|
||||||
"description": "Personal website",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
print(f"Error getting git data: {e}")
|
|
||||||
|
|
||||||
return jsonify({
|
|
||||||
"repo_name": repo_name,
|
|
||||||
"repo_description": repo_description,
|
|
||||||
"git": git,
|
|
||||||
})
|
|
||||||
|
|
||||||
# endregion
|
|
||||||
|
|
||||||
# region Misc routes
|
# region Misc routes
|
||||||
|
|
||||||
|
|
||||||
@@ -530,6 +210,17 @@ def links_get():
|
|||||||
def generator_get():
|
def generator_get():
|
||||||
return render_template(request.path.split("/")[-2] + ".html")
|
return render_template(request.path.split("/")[-2] + ".html")
|
||||||
|
|
||||||
|
@app.route("/api/<path:function>")
|
||||||
|
def api_old_get(function):
|
||||||
|
return redirect(f"/api/v1/{function}", code=301)
|
||||||
|
|
||||||
|
@app.route("/actions.json")
|
||||||
|
def sol_actions_get():
|
||||||
|
return jsonify(
|
||||||
|
{"rules": [{"pathPattern": "/donate**", "apiPath": "/api/v1/donate**"}]}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|
||||||
# region Main routes
|
# region Main routes
|
||||||
@@ -729,138 +420,6 @@ def index_get():
|
|||||||
|
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
# region Now Pages
|
|
||||||
@app.route("/now")
|
|
||||||
@app.route("/now/")
|
|
||||||
def now_index_get():
|
|
||||||
global handshake_scripts
|
|
||||||
|
|
||||||
# If localhost, don't load handshake
|
|
||||||
if (
|
|
||||||
request.host == "localhost:5000"
|
|
||||||
or request.host == "127.0.0.1:5000"
|
|
||||||
or os.getenv("dev") == "true"
|
|
||||||
or request.host == "test.nathan.woodburn.au"
|
|
||||||
):
|
|
||||||
handshake_scripts = ""
|
|
||||||
|
|
||||||
return render_latest_now(handshake_scripts)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/now/<path:path>")
|
|
||||||
def now_path_get(path):
|
|
||||||
global handshake_scripts
|
|
||||||
# If localhost, don't load handshake
|
|
||||||
if (
|
|
||||||
request.host == "localhost:5000"
|
|
||||||
or request.host == "127.0.0.1:5000"
|
|
||||||
or os.getenv("dev") == "true"
|
|
||||||
or request.host == "test.nathan.woodburn.au"
|
|
||||||
):
|
|
||||||
handshake_scripts = ""
|
|
||||||
|
|
||||||
return render_now_page(path, handshake_scripts)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/old")
|
|
||||||
@app.route("/old/")
|
|
||||||
@app.route("/now/old")
|
|
||||||
@app.route("/now/old/")
|
|
||||||
def now_old_get():
|
|
||||||
global handshake_scripts
|
|
||||||
# If localhost, don't load handshake
|
|
||||||
if (
|
|
||||||
request.host == "localhost:5000"
|
|
||||||
or request.host == "127.0.0.1:5000"
|
|
||||||
or os.getenv("dev") == "true"
|
|
||||||
or request.host == "test.nathan.woodburn.au"
|
|
||||||
):
|
|
||||||
handshake_scripts = ""
|
|
||||||
|
|
||||||
now_dates = list_now_dates()[1:]
|
|
||||||
html = '<ul class="list-group">'
|
|
||||||
html += f'<a style="text-decoration:none;" href="/now"><li class="list-group-item" style="background-color:#000000;color:#ffffff;">{get_latest_now_date(True)}</li></a>'
|
|
||||||
|
|
||||||
for date in now_dates:
|
|
||||||
link = date
|
|
||||||
date = datetime.datetime.strptime(date, "%y_%m_%d")
|
|
||||||
date = date.strftime("%A, %B %d, %Y")
|
|
||||||
html += f'<a style="text-decoration:none;" href="/now/{link}"><li class="list-group-item" style="background-color:#000000;color:#ffffff;">{date}</li></a>'
|
|
||||||
|
|
||||||
html += "</ul>"
|
|
||||||
return render_template(
|
|
||||||
"now/old.html", handshake_scripts=handshake_scripts, now_pages=html
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/now.rss")
|
|
||||||
@app.route("/now.xml")
|
|
||||||
@app.route("/rss.xml")
|
|
||||||
def now_rss_get():
|
|
||||||
host = "https://" + request.host
|
|
||||||
if ":" in request.host:
|
|
||||||
host = "http://" + request.host
|
|
||||||
# Generate RSS feed
|
|
||||||
now_pages = list_now_page_files()
|
|
||||||
rss = f'<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Nathan.Woodburn/</title><link>{host}</link><description>See what I\'ve been up to</description><language>en-us</language><lastBuildDate>{datetime.datetime.now(tz=datetime.timezone.utc).strftime("%a, %d %b %Y %H:%M:%S %z")}</lastBuildDate><atom:link href="{host}/now.rss" rel="self" type="application/rss+xml" />'
|
|
||||||
for page in now_pages:
|
|
||||||
link = page.strip(".html")
|
|
||||||
date = datetime.datetime.strptime(link, "%y_%m_%d")
|
|
||||||
date = date.strftime("%A, %B %d, %Y")
|
|
||||||
rss += f'<item><title>What\'s Happening {date}</title><link>{host}/now/{link}</link><description>Latest updates for {date}</description><guid>{host}/now/{link}</guid></item>'
|
|
||||||
rss += "</channel></rss>"
|
|
||||||
return make_response(rss, 200, {"Content-Type": "application/rss+xml"})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/now.json")
|
|
||||||
def now_json_get():
|
|
||||||
now_pages = list_now_page_files()
|
|
||||||
host = "https://" + request.host
|
|
||||||
if ":" in request.host:
|
|
||||||
host = "http://" + request.host
|
|
||||||
now_pages = [{"url": host+"/now/"+page.strip(".html"), "date": datetime.datetime.strptime(page.strip(".html"), "%y_%m_%d").strftime(
|
|
||||||
"%A, %B %d, %Y"), "title": "What's Happening "+datetime.datetime.strptime(page.strip(".html"), "%y_%m_%d").strftime("%A, %B %d, %Y")} for page in now_pages]
|
|
||||||
return jsonify(now_pages)
|
|
||||||
|
|
||||||
# endregion
|
|
||||||
|
|
||||||
# region Blog Pages
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/blog")
|
|
||||||
@app.route("/blog/")
|
|
||||||
def blog_index_get():
|
|
||||||
global handshake_scripts
|
|
||||||
|
|
||||||
# If localhost, don't load handshake
|
|
||||||
if (
|
|
||||||
request.host == "localhost:5000"
|
|
||||||
or request.host == "127.0.0.1:5000"
|
|
||||||
or os.getenv("dev") == "true"
|
|
||||||
or request.host == "test.nathan.woodburn.au"
|
|
||||||
):
|
|
||||||
handshake_scripts = ""
|
|
||||||
|
|
||||||
return render_blog_home(handshake_scripts)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/blog/<path:path>")
|
|
||||||
def blog_path_get(path):
|
|
||||||
global handshake_scripts
|
|
||||||
# If localhost, don't load handshake
|
|
||||||
if (
|
|
||||||
request.host == "localhost:5000"
|
|
||||||
or request.host == "127.0.0.1:5000"
|
|
||||||
or os.getenv("dev") == "true"
|
|
||||||
or request.host == "test.nathan.woodburn.au"
|
|
||||||
):
|
|
||||||
handshake_scripts = ""
|
|
||||||
|
|
||||||
return render_blog_page(path, handshake_scripts)
|
|
||||||
|
|
||||||
# endregion
|
|
||||||
|
|
||||||
# region Donate
|
# region Donate
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
5
sol.py
5
sol.py
@@ -40,3 +40,8 @@ def create_transaction(sender_address: str, amount: float) -> str:
|
|||||||
raw_bytes = binascii.unhexlify(tx)
|
raw_bytes = binascii.unhexlify(tx)
|
||||||
base64_string = base64.b64encode(raw_bytes).decode("utf-8")
|
base64_string = base64.b64encode(raw_bytes).decode("utf-8")
|
||||||
return base64_string
|
return base64_string
|
||||||
|
|
||||||
|
def get_solana_address() -> str:
|
||||||
|
if SOLANA_ADDRESS is None:
|
||||||
|
raise ValueError("SOLANA_ADDRESS is not set. Please ensure the .well-known/wallets/SOL file exists and contains a valid address.")
|
||||||
|
return str(SOLANA_ADDRESS)
|
||||||
Reference in New Issue
Block a user