|
|
|
# IMPORT
|
|
|
|
import os
|
|
|
|
|
|
|
|
from flask import Flask, render_template, request, url_for, redirect, jsonify, abort, send_from_directory
|
|
|
|
import markdown
|
|
|
|
import subprocess
|
|
|
|
import frontmatter
|
|
|
|
from datetime import datetime
|
|
|
|
import json
|
|
|
|
|
|
|
|
|
|
|
|
# FUNCTIONS
|
|
|
|
|
|
|
|
def list_files(folder, remove_ext=False):
|
|
|
|
''' Read all the functions in a folder '''
|
|
|
|
names = []
|
|
|
|
for entry in os.scandir(folder):
|
|
|
|
# add to the list only proper files
|
|
|
|
if entry.is_file(follow_symlinks=False):
|
|
|
|
# remove the extension from the filename
|
|
|
|
n = os.path.splitext(entry.name)[0]
|
|
|
|
if remove_ext:
|
|
|
|
n = entry.name
|
|
|
|
names.append(n)
|
|
|
|
return names
|
|
|
|
|
|
|
|
|
|
|
|
def list_folders(folder):
|
|
|
|
''' Return all the folders in a folder '''
|
|
|
|
names = []
|
|
|
|
for entry in os.scandir(folder):
|
|
|
|
# add to the list only proper files
|
|
|
|
if not entry.name.startswith('.') and entry.is_dir():
|
|
|
|
# remove the extension from the filename
|
|
|
|
names.append(entry.name)
|
|
|
|
return names
|
|
|
|
|
|
|
|
|
|
|
|
def get_md_contents(filename, directory='./contents'):
|
|
|
|
''' Return contents from a filename as frontmatter handler '''
|
|
|
|
with open(f"{directory}/{filename}", "r") as f:
|
|
|
|
metadata, content = frontmatter.parse(f.read())
|
|
|
|
html_content = markdown.markdown(content, extensions=[
|
|
|
|
'markdown.extensions.attr_list', 'markdown.extensions.codehilite', 'markdown.extensions.fenced_code'])
|
|
|
|
return metadata, html_content
|
|
|
|
|
|
|
|
|
|
|
|
def render_home():
|
|
|
|
print('Rendering home...')
|
|
|
|
with open('/home/kamo/public_html/render.html', 'w') as f:
|
|
|
|
# get the basic info of the website from the /contents/home.md file
|
|
|
|
meta, content = get_md_contents("home.md")
|
|
|
|
projects_list = []
|
|
|
|
for project in list_folders("./projects"):
|
|
|
|
project_info = get_md_contents(f"{project}.md",
|
|
|
|
f"./{projects}/{project}")[0]
|
|
|
|
project_date = datetime.strptime(project_info['date'], '%d/%m/%Y')
|
|
|
|
project_info['date'] = datetime.strftime(project_date, '%d %b, %y')
|
|
|
|
project_info['categories'].sort()
|
|
|
|
|
|
|
|
project_info['slug'] = project
|
|
|
|
projects_list.append(project_info)
|
|
|
|
|
|
|
|
projects_list.sort(reverse=True, key=lambda project: datetime.strptime(
|
|
|
|
project['date'], '%d %b, %y'))
|
|
|
|
|
|
|
|
# get the list of the projects, the functions, and the corpora
|
|
|
|
home = {
|
|
|
|
**meta,
|
|
|
|
"content": content,
|
|
|
|
"projects": projects_list
|
|
|
|
}
|
|
|
|
f.write(render_template("home.html", **home))
|
|
|
|
print('Rendered!')
|
|
|
|
|
|
|
|
|
|
|
|
# FLASK APP
|
|
|
|
|
|
|
|
class PrefixMiddleware(object):
|
|
|
|
def __init__(self, app, prefix=""):
|
|
|
|
self.app = app
|
|
|
|
self.prefix = prefix
|
|
|
|
|
|
|
|
def __call__(self, environ, start_response):
|
|
|
|
|
|
|
|
if environ["PATH_INFO"].startswith(self.prefix):
|
|
|
|
environ["PATH_INFO"] = environ["PATH_INFO"][len(self.prefix) :]
|
|
|
|
environ["SCRIPT_NAME"] = self.prefix
|
|
|
|
return self.app(environ, start_response)
|
|
|
|
else:
|
|
|
|
start_response("404", [("Content-Type", "text/plain")])
|
|
|
|
return ["This url does not belong to the app.".encode()]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
projects = 'projects'
|
|
|
|
|
|
|
|
# create flask application
|
|
|
|
app = Flask(__name__)
|
|
|
|
app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix='/soupboat/~kamo')
|
|
|
|
|
|
|
|
# Homepage
|
|
|
|
@app.route("/")
|
|
|
|
def home_page():
|
|
|
|
return send_from_directory(app.root_path, 'render.html')
|
|
|
|
|
|
|
|
|
|
|
|
# For generic pages we can include a common template and change only the contents
|
|
|
|
@app.route("/<slug>/")
|
|
|
|
def dynamic_page(slug=None):
|
|
|
|
# meta is a dictionary that contains all the attributes in the markdown file (ex: title, description, soup, etc)
|
|
|
|
# content is the body of the md file aka the text content
|
|
|
|
# in this way we can access those frontmatter attributes in jinja simply using the variables title, description, soup, etc
|
|
|
|
meta, content = get_md_contents(f"{slug}.md")
|
|
|
|
return render_template("page.html", **meta, content=content)
|
|
|
|
|
|
|
|
|
|
|
|
# Single project
|
|
|
|
@app.route("/projects/<project>/")
|
|
|
|
def p_info(project=None):
|
|
|
|
meta, content = get_md_contents(f"{project}.md",
|
|
|
|
f"./{projects}/{project}")
|
|
|
|
template = 'project.html'
|
|
|
|
if 'template' in meta:
|
|
|
|
template = meta['template']
|
|
|
|
return render_template(template, **meta, content=content)
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/projects/<project>/<path:filename>')
|
|
|
|
def sendStaticFiles(project, filename):
|
|
|
|
return send_from_directory(app.root_path + f'/projects/{project}/', filename, conditional=True)
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/hook/', methods=['GET', 'POST'])
|
|
|
|
def pull():
|
|
|
|
if request.method == 'POST':
|
|
|
|
subprocess.call(['sh', '/home/kamo/public_html/update.sh'])
|
|
|
|
|
|
|
|
print('Request for rendering')
|
|
|
|
render_home()
|
|
|
|
|
|
|
|
with open('/home/kamo/public_html/log.txt', 'a') as f:
|
|
|
|
f.write(request.form['payload'])
|
|
|
|
print(request.form['payload'])
|
|
|
|
|
|
|
|
return 'Updated'
|
|
|
|
return 'GET method not supported'
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/render/')
|
|
|
|
def render():
|
|
|
|
print('Request for rendering')
|
|
|
|
render_home()
|
|
|
|
return redirect(url_for('home_page'))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# RUN
|
|
|
|
app.run(port="3132")
|