From 9f3096cbcf772b14250f492cfe0dc0ba04767e7e Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Fri, 3 Jun 2016 12:20:33 -0700 Subject: [PATCH] Add bootstrap script for fast dev environment setup --- .gitignore | 5 +- README.md | 5 ++ bootstrap.py | 82 ++++++++++++++++++++++++++++++ kirsle_legacy.py | 127 +++++++++++++++++++++++++++++++++++++++++++++++ settings.yml | 9 ++-- 5 files changed, 221 insertions(+), 7 deletions(-) create mode 100755 bootstrap.py create mode 100644 kirsle_legacy.py diff --git a/.gitignore b/.gitignore index 785bc28..1e20b18 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ -prod.ini -db +/prod.ini +/db +/rophako /www/static/photos/*.jpg /www/static/photos/*.png /www/static/photos/*.gif diff --git a/README.md b/README.md index 00f2acd..65ce282 100644 --- a/README.md +++ b/README.md @@ -16,3 +16,8 @@ my various software projects, and the `creativity/` and `wizards` folders. So, feel free to look around in this repo, but you won't find anything too interesting in here. It's mostly just Jinja2 HTML templates and the odd web design file (CSS, JS, and some images). + +## Dev Environment Quick Start + +Run `bootstrap.py` to automatically clone and configure the Rophako CMS to run +a local dev instance of Kirsle.net. diff --git a/bootstrap.py b/bootstrap.py new file mode 100755 index 0000000..54c3ef2 --- /dev/null +++ b/bootstrap.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 + +"""Bootstrap script to set up a local dev instance of Kirsle.net + +This will `git clone` an instance of the Rophako CMS and configure it to run +this local website. When the dev Rophako instance already exists, running this +script again acts as a shortcut to running `python runserver.py` from within +the Rophako git repo. + +This script is only designed to work in Python 3 and requires the `git` and +`pyvenv` commands. + +This performs the following tasks: +* Clones Rophako into ./rophako +* Sets up a Python 3 virtual environment via `pyvenv` at ./rophako/pyvenv +* Installs requirements via `pip` into its virtual environment +* Symlinks settings.yml and kirsle_legacy.py into the Rophako root +* Runs the server +""" + +import os +import os.path +import subprocess +import sys + +def main(): + # Make sure we have everything we need. + check_depends() + + # Do we already have Rophako? + if os.path.isdir("./rophako"): + os.chdir("./rophako") + else: + # Clone it. + must_run(["git", "clone", "https://github.com/kirsle/rophako"]) + os.chdir("./rophako") + + # Make the Python environment. + must_run(["pyvenv", "pyvenv"]) + must_run(["pyvenv/bin/pip", "install", "-r", "requirements.txt"]) + + # Configure it. + os.symlink("../settings.yml", "settings.yml") + os.symlink("../kirsle_legacy.py", "kirsle_legacy.py") + + print("=" * 80) + print("Success! Rophako has been cloned and configured! The server") + print("will now start. To quickly start the server again in the") + print("future, just run bootstrap.py again.") + print("=" * 80) + + # Run Rophako. + must_run(["pyvenv/bin/python", "runserver.py"]) + +def check_depends(): + # Make sure we have access to required commands. + errors = False + for command in [ "git", "pyvenv" ]: + try: + subprocess.check_call(["which", command], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + except subprocess.CalledProcessError: + print("You seem to be missing the command: {}".format(command)) + errors = True + + if errors: + print("Make sure the required commands are installed and try again.") + sys.exit(1) + +def must_run(args, **kwargs): + """Calls subprocess to run a command which must succeed or die.""" + result = subprocess.call(args, **kwargs) + if result != 0: + print("Errors were detected in the command I tried to run: {}".format( + " ".join(args), + )) + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/kirsle_legacy.py b/kirsle_legacy.py new file mode 100644 index 0000000..b7c02e4 --- /dev/null +++ b/kirsle_legacy.py @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- + +# Legacy endpoint compatibility from kirsle.net. + +from flask import g, request, redirect, url_for, flash +import re +import os +import json + +from rophako.settings import Config +from rophako.app import app +from rophako.utils import template, login_required +import rophako.model.blog as Blog +import rophako.jsondb as JsonDB + + +@app.route("/+") +def google_plus(): + return redirect("https://plus.google.com/+NoahPetherbridge/posts") + + +@app.route("/blog.html") +def ancient_legacy_blog(): + post_id = request.args.get("id", None) + if post_id is None: + return redirect(url_for("blog.index")) + + # Look up the friendly ID. + post = Blog.get_entry(post_id) + if not post: + flash("That blog entry wasn't found.") + return redirect(url_for("blog.index")) + + return redirect(url_for("blog.entry", fid=post["fid"]), code=301) + + +@app.route("/blog/kirsle/") +def legacy_blog(fid): + return redirect(url_for("blog.entry", fid=fid), code=301) + + +@app.route("/rss.cgi") +def legacy_rss(): + return redirect(url_for("blog.rss"), code=301) + + +@app.route("/firered/") +@app.route("/firered") +def legacy_firered(page=""): + g.info["page"] = str(page) or "1" + return template("firered.html") + + +@app.route("/download", methods=["GET", "POST"]) +def legacy_download(): + form = None + if request.method == "POST": + form = request.form + else: + # CNET links to the MS-DOS download using semicolon delimiters in the + # query string. Fix that if detected. + query = request.query_string.decode() + if not '&' in query and ';' in query: + url = re.sub(r';|%3b', '&', request.url, flags=re.IGNORECASE) + return redirect(url) + + form = request.args + + method = form.get("method", "index") + project = form.get("project", "") + filename = form.get("file", "") + + root = "/home/kirsle/www/projects" + + if project and filename: + # Filter the sections. + project = re.sub(r'[^A-Za-z0-9]', '', project) # Project name is alphanumeric only. + filename = re.sub(r'[^A-Za-z0-9\-_\.]', '', filename) + + # Check that all the files exist. + if os.path.isdir(os.path.join(root, project)) and os.path.isfile(os.path.join(root, project, filename)): + # Hit counters. + hits = { "hits": 0 } + db = "data/downloads/{}-{}".format(project, filename) + if JsonDB.exists(db.format(project, filename)): + hits = JsonDB.get(db) + + # Actually getting the file? + if method == "get": + # Up the hit counter. + hits["hits"] += 1 + JsonDB.commit(db, hits) + + g.info["method"] = method + g.info["project"] = project + g.info["file"] = filename + g.info["hits"] = hits["hits"] + return template("download.html") + + flash("The file or project wasn't found.") + return redirect(url_for("index")) + + +@app.route("/.html") +def legacy_url(page): + return redirect("/{}".format(page), code=301) + + +@app.route("/metacity") +def legacy_metacity(): + return redirect("https://github.com/kirsle/linux-themes", code=301) + + +@app.route("/ssl_test") +@login_required +def ssl_test(): + return "
{}
".format(json.dumps({ + "SSLify criteria": { + "request.is_secure": request.is_secure, + "app.debug": app.debug, + "X-Forwarded-Proto is http": request.headers.get("X-Forwarded-Proto", "http") == "https", + }, + "App Configuration": { + "Session cookies secure": app.config["SESSION_COOKIE_SECURE"], + "config.FORCE_SSL": Config.security.force_ssl, + }, + })) diff --git a/settings.yml b/settings.yml index 988b7ad..7ecec97 100644 --- a/settings.yml +++ b/settings.yml @@ -2,14 +2,13 @@ rophako: site: debug: false site_name: kirsle.net - site_root: /home/kirsle/git/kirsle.net/www + site_root: ../www security: - force_ssl: true secret_key: something random use_forwarded_for: true db: - db_root: /home/kirsle/git/kirsle.net/db - redis_db: 1 + db_root: db + redis_prefix: "kirsle.net:" mail: sender: Kirsle.net blog: @@ -20,6 +19,6 @@ rophako: image_url: https://www.kirsle.net/static/avatars/casey.png image_description: Kirsle.net photo: - root_private: /home/kirsle/www/static/photos + root_private: ../www/static/photos custom: - kirsle_legacy