diff options
-rw-r--r-- | .travis.yml | 4 | ||||
-rw-r--r-- | deploy.py | 21 | ||||
-rw-r--r-- | gunicorn_config.py | 46 | ||||
-rw-r--r-- | pysite/base_route.py | 22 | ||||
-rw-r--r-- | pysite/route_manager.py | 59 | ||||
-rw-r--r-- | pysite/views/healthcheck.py | 7 | ||||
-rw-r--r-- | pysite/views/index.py | 6 | ||||
-rw-r--r-- | pysite/views/invite.py | 7 | ||||
-rw-r--r-- | requirements-ci.txt | 17 | ||||
-rw-r--r-- | requirements.txt | 3 | ||||
-rw-r--r-- | static/favicon.ico | bin | 0 -> 28957 bytes | |||
-rw-r--r-- | static/logos/logo_banner.png | bin | 0 -> 54554 bytes | |||
-rw-r--r-- | templates/.gitkeep | 0 | ||||
-rw-r--r-- | templates/base.html | 17 | ||||
-rw-r--r-- | templates/index.html | 9 | ||||
-rw-r--r-- | templates/navigation.html | 19 |
16 files changed, 208 insertions, 29 deletions
diff --git a/.travis.yml b/.travis.yml index 90ae14fd..30032dfe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,11 @@ language: python python: - "3.6" - + install: - pip install -r requirements.txt - pip install -r requirements-ci.txt script: - snekchek after_success: - "curl $AUTODEPLOY_WEBHOOK -H \"token: $AUTODEPLOY_TOKEN\""
\ No newline at end of file + - python deploy.py diff --git a/deploy.py b/deploy.py new file mode 100644 index 00000000..189b5f0c --- /dev/null +++ b/deploy.py @@ -0,0 +1,21 @@ +import os + +import requests + + +branch = os.environ.get("TRAVIS_BRANCH") +url = os.environ.get("AUTODEPLOY_WEBHOOK") +token = os.environ.get("AUTODEPLOY_TOKEN") + +PR = os.environ.get("TRAVIS_PULL_REQUEST") + +print('branch:', branch) +print('is_pr:', PR) + +if branch == 'master' and PR == 'false': + print("deploying..") + result = requests.get(url=url, headers={'token': token}) + print(result.text) + +else: + print("skipping deploy") diff --git a/gunicorn_config.py b/gunicorn_config.py new file mode 100644 index 00000000..34d9fa55 --- /dev/null +++ b/gunicorn_config.py @@ -0,0 +1,46 @@ +def when_ready(server): + """ server hook that only runs when the gunicorn master process loads """ + + import os + import traceback + import rethinkdb as r + + try: + server.log.info("rethinkdb initialising") + + DB_HOST = os.environ.get("RETHINKDB_HOST") + DB_PORT = os.environ.get("RETHINKDB_PORT") + DB_DATABASE = os.environ.get("RETHINKDB_DATABASE") + DB_TABLE = os.environ.get("RETHINKDB_TABLE") + indexes = ['test'] + + conn = r.connect(host=DB_HOST, port=DB_PORT, db=DB_DATABASE) + + # Check if database exists, if not create it + db_exists = r.db_list().contains(DB_DATABASE).run(conn) + + if not db_exists: + server.log.info('adding database {0}'.format(DB_DATABASE)) + r.db_create(DB_DATABASE).run(conn) + + # Check if table exist, if not create it + table_exists = r.db(DB_DATABASE).table_list().contains(DB_TABLE).run(conn) + + if not table_exists: + server.log.info('adding table {0}'.format(DB_TABLE)) + r.db(DB_DATABASE).table_create(DB_TABLE).run(conn) + + # Check if index exists if not add it + rtable = r.db(DB_DATABASE).table(DB_TABLE) + current_indexes = rtable.index_list().run(conn) + + for index in indexes: + if index not in current_indexes: + server.log.info('adding index {0}'.format(index)) + rtable.index_create(index).run(conn) + + server.log.info("rethinkdb ready") + + except Exception as e: + server.log.error(traceback.format_exc()) + server.log.error("rethinkdb failed to initialise") diff --git a/pysite/base_route.py b/pysite/base_route.py index 4fdad857..916e7fae 100644 --- a/pysite/base_route.py +++ b/pysite/base_route.py @@ -1,23 +1,31 @@ # coding=utf-8 -from flask import Flask +from flask import Flask, render_template from flask.views import MethodView class BaseView(MethodView): - path = None #: str - name = None #: str + name = None # type: str + + def render(self, *template_names, **context): + context["current_page"] = self.name + context["view"] = self + + return render_template(template_names, **context) + + +class RouteView(BaseView): + path = None # type: str @classmethod - def setup(cls: "BaseView", app: Flask): + def setup(cls: "RouteView", app: Flask): if not cls.path or not cls.name: raise RuntimeError("Route views must have both `path` and `name` defined") app.add_url_rule(cls.path, view_func=cls.as_view(cls.name)) -class ErrorView(MethodView): - name = None #: str - error_code = None #: int +class ErrorView(BaseView): + error_code = None # type: int @classmethod def setup(cls: "ErrorView", app: Flask): diff --git a/pysite/route_manager.py b/pysite/route_manager.py index 5fe22ba0..09202d0c 100644 --- a/pysite/route_manager.py +++ b/pysite/route_manager.py @@ -3,20 +3,35 @@ import importlib import inspect import os -from flask import Flask +from flask import Flask, abort, g from pysite.base_route import BaseView, ErrorView +import rethinkdb + +from pysite.base_route import BaseView, ErrorView, RouteView + +DB_HOST = os.environ.get("RETHINKDB_HOST") +DB_PORT = os.environ.get("RETHINKDB_PORT") +DB_DATABASE = os.environ.get("RETHINKDB_DATABASE") +DB_TABLE = os.environ.get("RETHINKDB_TABLE") + +TEMPLATES_PATH = "../templates" +STATIC_PATH = "../static" class RouteManager: def __init__(self): - self.app = Flask(__name__) + self.app = Flask( + __name__, template_folder=TEMPLATES_PATH, static_folder=STATIC_PATH, static_url_path="/static", + ) self.app.secret_key = os.environ.get("WEBPAGE_SECRET_KEY") self.load_views() def run(self): - self.app.run(port=int(os.environ.get("WEBPAGE_PORT")), debug=False) + self.app.run( + port=int(os.environ.get("WEBPAGE_PORT")), debug="FLASK_DEBUG" in os.environ + ) def load_views(self, location="pysite/views"): for filename in os.listdir(location): @@ -33,7 +48,43 @@ class RouteManager: inspect.isclass(cls) and cls is not BaseView and cls is not ErrorView and - (BaseView in cls.__mro__ or ErrorView in cls.__mro__) + cls is not RouteView and + BaseView in cls.__mro__ ): cls.setup(self.app) print(f"View loaded: {cls.name: <25} ({module.__name__}.{cls_name})") + + def setup_db(self): + connection = self.get_db_connection(connect_database=False) + + try: + rethinkdb.db_create(DB_DATABASE).run(connection) + rethinkdb.db(DB_DATABASE).table_create(DB_TABLE).run(connection) + print("Database created") + except rethinkdb.RqlRuntimeError: + print("Database found") + finally: + connection.close() + + self.app.before_request(self.db_before_request) + self.app.teardown_request(self.db_teardown_request) + + def get_db_connection(self, connect_database=True): + if connect_database: + return rethinkdb.connect(host=DB_HOST, port=DB_PORT, db=DB_DATABASE) + else: + return rethinkdb.connect(host=DB_HOST, port=DB_PORT) + + def db_before_request(self): + try: + # g is the Flask global context object + g.rdb_conn = self.get_db_connection() + except rethinkdb.RqlDriverError: + abort(503, "Database connection could be established.") + + def db_teardown_request(self, _): + try: + # g is the Flask global context object + g.rdb_conn.close() + except AttributeError: + pass diff --git a/pysite/views/healthcheck.py b/pysite/views/healthcheck.py index 3931100c..088bc7b3 100644 --- a/pysite/views/healthcheck.py +++ b/pysite/views/healthcheck.py @@ -1,10 +1,13 @@ # coding=utf-8 from flask import jsonify -from pysite.base_route import BaseView +from pysite.base_route import RouteView -class IndexView(BaseView): +__author__ = "Gareth Coles" + + +class IndexView(RouteView): path = "/healthcheck" name = "healthcheck" diff --git a/pysite/views/index.py b/pysite/views/index.py index 48a98fac..0c2d1578 100644 --- a/pysite/views/index.py +++ b/pysite/views/index.py @@ -1,10 +1,10 @@ # coding=utf-8 -from pysite.base_route import BaseView +from pysite.base_route import RouteView -class IndexView(BaseView): +class IndexView(RouteView): path = "/" name = "index" def get(self): - return "Coming soon:tm:" + return self.render("index.html") diff --git a/pysite/views/invite.py b/pysite/views/invite.py index 65cd75a5..07ddc830 100644 --- a/pysite/views/invite.py +++ b/pysite/views/invite.py @@ -1,10 +1,13 @@ # coding=utf-8 from flask import redirect -from pysite.base_route import BaseView +from pysite.base_route import RouteView -class InviteView(BaseView): +__author__ = "Gareth Coles" + + +class InviteView(RouteView): path = "/invite" name = "invite" diff --git a/requirements-ci.txt b/requirements-ci.txt index 04e3aabe..50d0f297 100644 --- a/requirements-ci.txt +++ b/requirements-ci.txt @@ -1,9 +1,10 @@ -snekchek -flake8 -flake8-bugbear -flake8-bandit -flake8-import-order -flake8-tidy-imports -flake8-string-format -safety +snekchek +flake8 +flake8-bugbear +flake8-bandit +flake8-import-order +flake8-tidy-imports +flake8-string-format +safety dodgy +requests diff --git a/requirements.txt b/requirements.txt index 69ca547f..e6a3877f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ -flask==0.12.2
\ No newline at end of file +flask==0.12.2 +rethinkdb diff --git a/static/favicon.ico b/static/favicon.ico Binary files differnew file mode 100644 index 00000000..046480bf --- /dev/null +++ b/static/favicon.ico diff --git a/static/logos/logo_banner.png b/static/logos/logo_banner.png Binary files differnew file mode 100644 index 00000000..3036fb19 --- /dev/null +++ b/static/logos/logo_banner.png diff --git a/templates/.gitkeep b/templates/.gitkeep deleted file mode 100644 index e69de29b..00000000 --- a/templates/.gitkeep +++ /dev/null diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 00000000..9e00af20 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + {% block head %} + <title>Python | {% block title %}{% endblock %}</title> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <script defer src="https://use.fontawesome.com/releases/v5.0.6/js/all.js"></script> + <script defer src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.39/js/uikit.min.js"></script> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.39/css/uikit.min.css" /> + {% endblock %} +</head> +<body> +{% include "navigation.html" %} +{% block content %}{% endblock %} +</body> +</html>
\ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 00000000..418347d2 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,9 @@ +{% extends "base.html" %} +{% block title %}Home{% endblock %} +{% block content %} + <div class="uk-container uk-section"> + <h1 class="uk-title uk-text-center"> + Coming soon :tm: + </h1> + </div> +{% endblock %}
\ No newline at end of file diff --git a/templates/navigation.html b/templates/navigation.html new file mode 100644 index 00000000..cbd6a36a --- /dev/null +++ b/templates/navigation.html @@ -0,0 +1,19 @@ +<div class="uk-container uk-container-expand uk-section-secondary"> + <nav data-uk-navbar class="uk-navbar-container uk-navbar-transparent"> + <div class="uk-navbar-left"> + <a href="/" class="uk-navbar-item uk-logo"> + <img src="/static/logos/logo_banner.png" style="height: 50px;"/> + </a> + </div> + <div class="uk-navbar-right"> + <ul class="uk-navbar-nav"> + {% if current_page == "index" %} + <li class="uk-active"><a href="/"><i class="uk-icon fas fa-home"></i> Home</a></li> + {% else %} + <li><a href="/"><i class="uk-icon fas fa-home"></i> Home</a></li> + {% endif %} + <li><a href="/invite"><i class="uk-icon fab fa-discord"></i> Discord</a></li> + </ul> + </div> + </nav> +</div>
\ No newline at end of file |