Skip to content
Snippets Groups Projects
Commit 841a4bfe authored by Martin Mareš's avatar Martin Mareš
Browse files

Merge branch 'mj/assets' into 'devel'

Verzování statických souborů

See merge request !26
parents 33686841 ebc92823
No related branches found
No related tags found
1 merge request!26Verzování statických souborů
server {
listen 195.113.20.177:443 ssl;
listen [2001:718:1e03:801::b1]:443 ssl;
server_name mo.mff.cuni.cz;
ssl on;
ssl_certificate /etc/ssl/domains/mo.mff.cuni.cz/bundle.pem;
ssl_certificate_key /etc/ssl/domains/mo.mff.cuni.cz/privkey.pem;
ssl_dhparam /etc/ssl/dhparams.pem;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 5m;
client_max_body_size 1G;
### Production instance of OSMO
location /osmo {
include uwsgi_params;
uwsgi_pass unix:/akce/mo/osmo/var/osmo.sock;
}
location /osmo/static/ {
alias /akce/mo/osmo/static/;
}
location /osmo/assets/ {
location ~ ^/osmo/assets/[^/]+/(.*) {
alias /akce/mo/osmo/static/$1;
}
return 404;
}
location = /osmo/favicon.ico {
alias /akce/mo/osmo/static/favicon.ico;
}
}
...@@ -23,4 +23,5 @@ virtualenv = venv ...@@ -23,4 +23,5 @@ virtualenv = venv
manage-script-name = true manage-script-name = true
mule mule
static-map = /static=static # Můžeme také pomocí uwsgi servírovat static. Lepší je to dělat Nginxem.
# static-map = /static=static
# mo.ext does nothing by itself
pass
# Flask extension for versioned assets
from flask import send_from_directory
import hashlib
import os
from typing import Sequence, Dict
class Assets:
asset_dir: str
asset_dict: Dict[str, str]
url_prefix: str
def __init__(self, app, url_prefix: str, asset_dir: str):
self.app = app
if app is not None:
self.init_app(app, url_prefix, asset_dir)
def init_app(self, app, url_prefix: str, asset_dir: str):
self.asset_folder = asset_dir
self.asset_dict = {}
self.url_prefix = url_prefix
self.app = app
app.jinja_env.globals.update(asset_url=lambda name: self.asset_url(name))
app.assets = self
# This is usually needed only for development, production requests are handled by upstream proxy
app.add_url_rule(
url_prefix + "/<version>/<path:name>",
endpoint="assets",
view_func=lambda version, name: self.send_asset(name),
)
def add_asset(self, name: str):
if name in self.asset_dict:
return
file_name = os.path.join(self.asset_folder, name)
digest = hashlib.sha1()
with open(file_name, 'rb') as file:
while True:
block = file.read(4096)
if not block:
break
digest.update(block)
version = digest.hexdigest()[:8]
self.app.logger.debug(f'Assets: Loaded {name}: version {version}')
self.asset_dict[name] = version
def add_assets(self, names: Sequence[str]):
for name in names:
self.add_asset(name)
def asset_url(self, name: str) -> str:
assert name in self.asset_dict
return os.path.join(self.url_prefix, self.asset_dict[name], name)
def send_asset(self, name: str):
return send_from_directory(self.asset_folder, name)
...@@ -14,6 +14,7 @@ import werkzeug.formparser ...@@ -14,6 +14,7 @@ import werkzeug.formparser
import mo import mo
import mo.config as config import mo.config as config
import mo.db as db import mo.db as db
import mo.ext.assets
import mo.jobs import mo.jobs
import mo.rights import mo.rights
import mo.users import mo.users
...@@ -107,6 +108,15 @@ def setup_logging(): ...@@ -107,6 +108,15 @@ def setup_logging():
setup_logging() setup_logging()
# Incializace assetového mechanismu
mo.ext.assets.Assets(app, url_prefix='/assets', asset_dir=static_dir)
app.assets.add_assets([
'bootstrap.min.css',
'mo.css',
])
# Inicializace požadavků a nucená autorizace # Inicializace požadavků a nucená autorizace
class NeedLoginError(werkzeug.exceptions.Forbidden): class NeedLoginError(werkzeug.exceptions.Forbidden):
...@@ -120,7 +130,7 @@ def need_login(): ...@@ -120,7 +130,7 @@ def need_login():
def init_request(): def init_request():
path = request.path path = request.path
if path.startswith('/static/'): if path.startswith('/static/') or path.startswith('/assets/'):
# Pro statické soubory v development nasazení nepotřebujeme nastavovat # Pro statické soubory v development nasazení nepotřebujeme nastavovat
# nic dalšího (v ostrém nasazení je servíruje uwsgi) # nic dalšího (v ostrém nasazení je servíruje uwsgi)
return return
......
# Konfigurace Jinjový šablon a pomocné funkce # Konfigurace Jinjových šablon a pomocné funkce
from flask import url_for from flask import url_for
from markupsafe import Markup from markupsafe import Markup
...@@ -45,6 +45,7 @@ app.jinja_env.globals.update(Markup=Markup) ...@@ -45,6 +45,7 @@ app.jinja_env.globals.update(Markup=Markup)
app.jinja_env.globals.update(contest_breadcrumbs=contest_breadcrumbs) app.jinja_env.globals.update(contest_breadcrumbs=contest_breadcrumbs)
app.jinja_env.globals.update(place_breadcrumbs=place_breadcrumbs) app.jinja_env.globals.update(place_breadcrumbs=place_breadcrumbs)
# Funkce asset_url se přidává v mo.ext.assets
@app.template_filter() @app.template_filter()
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
<html> <html>
<head> <head>
<title>Odevzdávací systém MO: {% block title %}{% endblock %}</title> <title>Odevzdávací systém MO: {% block title %}{% endblock %}</title>
<link rel=stylesheet href="{{ url_for('static', filename='bootstrap.min.css') }}?v=2" type='text/css' media=all> <link rel=stylesheet href="{{ asset_url('bootstrap.min.css') }}" type='text/css' media=all>
<link rel=stylesheet href="{{ url_for('static', filename='mo.css') }}?v=7" type='text/css' media=all> <link rel=stylesheet href="{{ asset_url('mo.css') }}" type='text/css' media=all>
{% block head %}{% endblock %} {% block head %}{% endblock %}
</head> </head>
<body> <body>
......
...@@ -6,7 +6,7 @@ setuptools.setup( ...@@ -6,7 +6,7 @@ setuptools.setup(
name='osmo', name='osmo',
version='0.1', version='0.1',
description='Odevzdávací systém Matematické olympiády', description='Odevzdávací systém Matematické olympiády',
packages=['mo', 'mo/jobs', 'mo/web'], packages=['mo', 'mo/ext', 'mo/jobs', 'mo/web'],
scripts=[ scripts=[
'bin/add-role', 'bin/add-role',
'bin/create-contests', 'bin/create-contests',
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment