# 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(): with open(app.root_path + '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)) # 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("//") 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//") 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//') 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']) with open(app.root_path + '/log.txt', 'a') as f: f.write(request.form['payload']) print(request.form['payload']) render_home() return 'Updated' return 'GET method not supported' @app.route('/api/render/') def render(): render_home() return 'rendered' # RUN app.run(port="3132")