mirror of
https://github.com/Tygs/0bin.git
synced 2023-08-10 21:13:00 +03:00
Merge branch 'v2' of github.com:Tygs/0bin into v2
This commit is contained in:
commit
836fa17bc4
@ -1,6 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# coding: utf-8
|
|
||||||
|
|
||||||
from zerobin.cmd import main
|
|
||||||
|
|
||||||
main()
|
|
5
zerobin/__main__.py
Normal file
5
zerobin/__main__.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from zerobin.cli import main
|
||||||
|
|
||||||
|
main()
|
@ -7,16 +7,20 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
|
import os
|
||||||
|
|
||||||
|
import zerobin
|
||||||
|
|
||||||
from zerobin.utils import (
|
from zerobin.utils import (
|
||||||
settings,
|
settings,
|
||||||
SettingsValidationError,
|
SettingsValidationError,
|
||||||
ensure_var_env,
|
ensure_app_context,
|
||||||
hash_password,
|
hash_password,
|
||||||
)
|
)
|
||||||
from zerobin.routes import get_app
|
from zerobin.routes import get_app
|
||||||
from zerobin.paste import Paste
|
from zerobin.paste import Paste
|
||||||
|
|
||||||
|
|
||||||
from bottle import run
|
from bottle import run
|
||||||
|
|
||||||
import clize
|
import clize
|
||||||
@ -26,11 +30,9 @@ def runserver(
|
|||||||
*,
|
*,
|
||||||
host="",
|
host="",
|
||||||
port="",
|
port="",
|
||||||
|
config_dir="",
|
||||||
|
data_dir="",
|
||||||
debug=None,
|
debug=None,
|
||||||
user="",
|
|
||||||
group="",
|
|
||||||
settings_file="",
|
|
||||||
compressed_static=None,
|
|
||||||
version=False,
|
version=False,
|
||||||
paste_id_length=None,
|
paste_id_length=None,
|
||||||
server="paste",
|
server="paste",
|
||||||
@ -39,23 +41,18 @@ def runserver(
|
|||||||
print("0bin V%s" % settings.VERSION)
|
print("0bin V%s" % settings.VERSION)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
settings.HOST = host or settings.HOST
|
|
||||||
settings.PORT = port or settings.PORT
|
|
||||||
settings.USER = user or settings.USER
|
|
||||||
settings.GROUP = group or settings.GROUP
|
|
||||||
settings.PASTE_ID_LENGTH = paste_id_length or settings.PASTE_ID_LENGTH
|
|
||||||
settings.DEBUG = bool(debug) if debug is not None else settings.DEBUG
|
|
||||||
|
|
||||||
ensure_var_env()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
_, app = get_app(debug, settings_file, compressed_static, settings=settings)
|
settings, app = get_app(debug=debug, config_dir=config_dir, data_dir=data_dir,)
|
||||||
except SettingsValidationError as err:
|
except SettingsValidationError as err:
|
||||||
print("Configuration error: %s" % err.message, file=sys.stderr)
|
print("Configuration error: %s" % err.message, file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
settings.HOST = host or os.environ.get("ZEROBIN_HOST", settings.HOST)
|
||||||
|
settings.PORT = port or os.environ.get("ZEROBIN_PORT", settings.PORT)
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
print(f"Admin URL: http://{settings.HOST}:{settings.PORT}{settings.ADMIN_URL}")
|
print(f"Admin URL: {settings.ADMIN_URL}")
|
||||||
|
print()
|
||||||
run(
|
run(
|
||||||
app, host=settings.HOST, port=settings.PORT, reloader=True, server=server,
|
app, host=settings.HOST, port=settings.PORT, reloader=True, server=server,
|
||||||
)
|
)
|
||||||
@ -100,7 +97,7 @@ def delete_paste(*pastes, quiet=False):
|
|||||||
print("Paste {} doesn't exist".format(paste_uuid))
|
print("Paste {} doesn't exist".format(paste_uuid))
|
||||||
|
|
||||||
|
|
||||||
def print_admin_url():
|
def infos():
|
||||||
""" Print the route to the 0bin admin.
|
""" Print the route to the 0bin admin.
|
||||||
|
|
||||||
The admin route is generated by zerobin so that bots won't easily
|
The admin route is generated by zerobin so that bots won't easily
|
||||||
@ -123,8 +120,16 @@ def print_admin_url():
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ensure_var_env()
|
ensure_app_context()
|
||||||
print(settings.ADMIN_URL)
|
print(f"Zerobin version: {zerobin.__version__}")
|
||||||
|
print(f"Admin URL (to moderate pastes): {settings.ADMIN_URL}")
|
||||||
|
print(f"Data dir (pastes and counter): {settings.DATA_DIR}")
|
||||||
|
print(
|
||||||
|
f"Config dir (config file, secret key, admin password and custom views): {settings.CONFIG_DIR}"
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
f"Static files dir (to configure apache, nging, etc.): {settings.STATIC_FILES_ROOT}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def set_admin_password(password):
|
def set_admin_password(password):
|
||||||
@ -134,17 +139,17 @@ def set_admin_password(password):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ensure_var_env()
|
ensure_app_context()
|
||||||
settings.ADMIN_PASSWORD_FILE.write_bytes(hash_password(password))
|
settings.ADMIN_PASSWORD_FILE.write_bytes(hash_password(password))
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
subcommands = [runserver, delete_paste, print_admin_url, set_admin_password]
|
subcommands = [runserver, delete_paste, infos, set_admin_password]
|
||||||
subcommand_names = [
|
subcommand_names = [
|
||||||
clize.util.name_py2cli(name)
|
clize.util.name_py2cli(name)
|
||||||
for name in clize.util.dict_from_names(subcommands).keys()
|
for name in clize.util.dict_from_names(subcommands).keys()
|
||||||
]
|
]
|
||||||
if len(sys.argv) < 2 or sys.argv[1] not in subcommand_names:
|
if len(sys.argv) < 2 or sys.argv[1] not in subcommand_names:
|
||||||
sys.argv.insert(1, subcommand_names[0])
|
sys.argv.insert(1, subcommand_names[0])
|
||||||
clize.run(runserver, delete_paste, print_admin_url, set_admin_password)
|
clize.run(runserver, delete_paste, infos, set_admin_password)
|
||||||
|
|
@ -1,57 +1,19 @@
|
|||||||
from zerobin import ROOT_DIR
|
# Get error messages and auto reload.
|
||||||
|
# Don't set this to True in production
|
||||||
# Path to the directory that will contains all variable content, such
|
|
||||||
# as pastes, the secret key, etc
|
|
||||||
VAR_DIR = ROOT_DIR.parent / "var"
|
|
||||||
|
|
||||||
# debug will get you error messages and auto reload
|
|
||||||
# don't set this to True in production
|
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
|
|
||||||
# Should the application serve static files on it's own ?
|
# Port and host the embedded python server should be using
|
||||||
# If yes, set the absolute path to the static files.
|
|
||||||
# If no, set it to None
|
|
||||||
# In dev this is handy, in prod you probably want the HTTP servers
|
|
||||||
# to serve it, but it's OK for small traffic to set it to True in prod too.
|
|
||||||
STATIC_FILES_ROOT = ROOT_DIR / "static"
|
|
||||||
|
|
||||||
# If True, will link the compressed verion of the js and css files,
|
|
||||||
# otherwise, will use the ordinary files
|
|
||||||
COMPRESSED_STATIC_FILES = False
|
|
||||||
|
|
||||||
# A tuple of absolute paths of directory where to look the template for
|
|
||||||
# the first one will be the first to be looked into
|
|
||||||
# if you want to override, it needs to be it a directory at the begining of
|
|
||||||
# this tuple. By default, custom_views is meant for that purpose.
|
|
||||||
TEMPLATE_DIRS = (
|
|
||||||
VAR_DIR / "custom_views",
|
|
||||||
ROOT_DIR / "views",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Port and host the embeded python server should be using
|
|
||||||
# You can also specify them using the --host and --port script options
|
|
||||||
# which have priority on these settings
|
|
||||||
HOST = "127.0.0.1"
|
HOST = "127.0.0.1"
|
||||||
PORT = "8000"
|
PORT = "3255"
|
||||||
|
|
||||||
# User and group the server should run as. Set to None if it should be the
|
|
||||||
# current user. Some OS don't support it and if so, it will be ignored.
|
|
||||||
USER = None
|
|
||||||
GROUP = None
|
|
||||||
|
|
||||||
# Display a tiny counter for pastes created.
|
# Display a tiny counter for pastes created.
|
||||||
# Be carreful if your site have to many pastes this can hurt your hard drive performances.
|
|
||||||
# Refresh counter interval. Default to every minute after a paste.
|
|
||||||
DISPLAY_COUNTER = True
|
DISPLAY_COUNTER = True
|
||||||
REFRESH_COUNTER = 60 * 1 # Fill this if you want to
|
# Refresh counter interval.
|
||||||
ADMIN_CREDENTIALS = {
|
REFRESH_COUNTER = 60 # in seconds
|
||||||
"username": None,
|
|
||||||
"password": None,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
# Names/links to insert in the footer.
|
||||||
# Names/links to insert in the menu bar.
|
# Any link with "mailto:" will be escaped to limit spam, but displayed
|
||||||
# Any link with "mailto:" will be escaped to prevent spam
|
# correctly to the user using JS.
|
||||||
MENU = (
|
MENU = (
|
||||||
("Create paste", "/"), # internal link. First link will be highlited
|
("Create paste", "/"), # internal link. First link will be highlited
|
||||||
("Github", "https://github.com/Tygs/0bin"), # external link
|
("Github", "https://github.com/Tygs/0bin"), # external link
|
||||||
@ -60,11 +22,11 @@ MENU = (
|
|||||||
("Zerobin Pastebin", "https://www.0bin.net/"), # Thanks the authors :)
|
("Zerobin Pastebin", "https://www.0bin.net/"), # Thanks the authors :)
|
||||||
)
|
)
|
||||||
|
|
||||||
# limit size of pasted text in bytes. Be careful allowing too much size can
|
# Size limit of the paste content in bytes. Be careful, allowing a size too big can
|
||||||
# slow down user's browser
|
# slow down the user's browser
|
||||||
MAX_SIZE = 1024 * 500
|
MAX_SIZE = 1024 * 500
|
||||||
|
|
||||||
# length of base64-like paste-id string in the url, int from 4 to 27 (length of sha1 digest)
|
# Length of the paste-id string in the url, int from 4 to 27 (length of sha1 digest)
|
||||||
# total number of unique pastes can be calculated as 2^(6*PASTE_ID_LENGTH)
|
# total number of unique pastes can be calculated as 2^(6*PASTE_ID_LENGTH)
|
||||||
# for PASTE_ID_LENGTH=8, for example, it's 2^(6*8) = 281 474 976 710 656
|
# for PASTE_ID_LENGTH=8, for example, it's 2^(6*8) = 281 474 976 710 656
|
||||||
PASTE_ID_LENGTH = 8
|
PASTE_ID_LENGTH = 8
|
||||||
|
@ -27,15 +27,15 @@ from beaker.middleware import SessionMiddleware
|
|||||||
|
|
||||||
from zerobin import __version__
|
from zerobin import __version__
|
||||||
from zerobin.utils import (
|
from zerobin.utils import (
|
||||||
settings,
|
|
||||||
SettingsValidationError,
|
SettingsValidationError,
|
||||||
ensure_var_env,
|
ensure_app_context,
|
||||||
check_password,
|
check_password,
|
||||||
|
settings,
|
||||||
)
|
)
|
||||||
from zerobin.paste import Paste
|
from zerobin.paste import Paste
|
||||||
|
|
||||||
|
|
||||||
ensure_var_env()
|
ensure_app_context()
|
||||||
|
|
||||||
|
|
||||||
GLOBAL_CONTEXT = {
|
GLOBAL_CONTEXT = {
|
||||||
@ -235,33 +235,33 @@ def server_static(filename):
|
|||||||
return static_file(filename, root=settings.STATIC_FILES_ROOT)
|
return static_file(filename, root=settings.STATIC_FILES_ROOT)
|
||||||
|
|
||||||
|
|
||||||
def get_app(debug=None, settings_file="", compressed_static=None, settings=settings):
|
def get_app(debug=None, config_dir="", data_dir=""):
|
||||||
"""
|
"""
|
||||||
Return a tuple (settings, app) configured using passed
|
Return a tuple (settings, app) configured using passed
|
||||||
parameters and/or a setting file.
|
parameters and/or a setting file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
settings_file = settings_file or os.environ.get("ZEROBIN_SETTINGS_FILE")
|
data_dir = data_dir or os.environ.get("ZEROBIN_DATA_DIR")
|
||||||
|
config_dir = config_dir or os.environ.get("ZEROBIN_CONFIG_DIR")
|
||||||
|
|
||||||
if settings_file:
|
ensure_app_context(config_dir=config_dir, data_dir=data_dir)
|
||||||
settings.update_with_file(os.path.realpath(settings_file))
|
|
||||||
|
settings.DEBUG = bool(debug or os.environ.get("ZEROBIN_DEBUG", settings.DEBUG))
|
||||||
|
|
||||||
|
settings.DISPLAY_COUNTER = bool(
|
||||||
|
os.environ.get("ZEROBIN_DISPLAY_COUNTER", settings.DISPLAY_COUNTER)
|
||||||
|
)
|
||||||
|
settings.REFRESH_COUNTER = int(
|
||||||
|
os.environ.get("ZEROBIN_REFRESH_COUNTER", settings.REFRESH_COUNTER)
|
||||||
|
)
|
||||||
|
settings.MAX_SIZE = int(os.environ.get("ZEROBIN_MAX_SIZE", settings.MAX_SIZE))
|
||||||
|
settings.PASTE_ID_LENGTH = int(
|
||||||
|
os.environ.get("ZEROBIN_PASTE_ID_LENGTH", settings.PASTE_ID_LENGTH)
|
||||||
|
)
|
||||||
|
|
||||||
if settings.PASTE_ID_LENGTH < 4:
|
if settings.PASTE_ID_LENGTH < 4:
|
||||||
raise SettingsValidationError("PASTE_ID_LENGTH cannot be lower than 4")
|
raise SettingsValidationError("PASTE_ID_LENGTH cannot be lower than 4")
|
||||||
|
|
||||||
if compressed_static is not None:
|
|
||||||
settings.COMPRESSED_STATIC_FILES = compressed_static
|
|
||||||
|
|
||||||
if debug is not None:
|
|
||||||
settings.DEBUG = debug
|
|
||||||
|
|
||||||
# make sure the templates can be loaded
|
|
||||||
for d in reversed(settings.TEMPLATE_DIRS):
|
|
||||||
bottle.TEMPLATE_PATH.insert(0, d)
|
|
||||||
|
|
||||||
if settings.DEBUG:
|
|
||||||
bottle.debug(True)
|
|
||||||
|
|
||||||
return settings, app
|
return settings, app
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,9 +46,6 @@
|
|||||||
|
|
||||||
/* body & other stuff */
|
/* body & other stuff */
|
||||||
|
|
||||||
body {
|
|
||||||
padding-bottom: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.blk-space {
|
.blk-space {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
@ -101,16 +98,24 @@ blockquote {
|
|||||||
|
|
||||||
/* Footer */
|
/* Footer */
|
||||||
|
|
||||||
|
#app {
|
||||||
|
display: flex;
|
||||||
|
min-height: 100vh;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
#wrap-content {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
bottom: 0px;
|
|
||||||
position: fixed;
|
|
||||||
height: 60px;
|
height: 60px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0px 0px 0px 0px;
|
margin: 0px 0px 0px 0px;
|
||||||
padding: 8px 0 0 0;
|
padding: 8px 0 0 0;
|
||||||
left: 0;
|
|
||||||
background-color: #424141;
|
background-color: #424141;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,8 +18,6 @@ setTimeout(function () {
|
|||||||
document.getElementById('content').focus()
|
document.getElementById('content').focus()
|
||||||
}, 100)
|
}, 100)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const app = new Vue({
|
const app = new Vue({
|
||||||
|
|
||||||
el: '#app',
|
el: '#app',
|
||||||
|
@ -8,6 +8,13 @@ import hashlib
|
|||||||
import secrets
|
import secrets
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import bottle
|
||||||
|
|
||||||
|
from appdirs import AppDirs
|
||||||
|
|
||||||
|
import zerobin
|
||||||
from zerobin import default_settings
|
from zerobin import default_settings
|
||||||
|
|
||||||
|
|
||||||
@ -92,7 +99,7 @@ def as_unicode(obj):
|
|||||||
return str(obj)
|
return str(obj)
|
||||||
|
|
||||||
|
|
||||||
def ensure_var_env():
|
def ensure_app_context(data_dir=None, config_dir=None):
|
||||||
""" Ensure all the variable things we generate are available.
|
""" Ensure all the variable things we generate are available.
|
||||||
|
|
||||||
This will make sure we have:
|
This will make sure we have:
|
||||||
@ -101,20 +108,39 @@ def ensure_var_env():
|
|||||||
- a content dir
|
- a content dir
|
||||||
- a secret key
|
- a secret key
|
||||||
- an admin URL
|
- an admin URL
|
||||||
|
|
||||||
|
This function is idempotent if nothing touch the files it created.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
settings.VAR_DIR.mkdir(exist_ok=True, parents=True)
|
app_dirs = AppDirs("0bin", "tygs")
|
||||||
settings.PASTE_FILES_ROOT = settings.VAR_DIR / "content"
|
|
||||||
|
settings.DATA_DIR = Path(data_dir or app_dirs.user_data_dir).expanduser()
|
||||||
|
settings.DATA_DIR.mkdir(exist_ok=True, parents=True)
|
||||||
|
|
||||||
|
settings.CONFIG_DIR = Path(config_dir or app_dirs.user_config_dir).expanduser()
|
||||||
|
settings.CONFIG_DIR.mkdir(exist_ok=True, parents=True)
|
||||||
|
|
||||||
|
settings.STATIC_FILES_ROOT = zerobin.ROOT_DIR / "static"
|
||||||
|
|
||||||
|
settings.PASTE_FILES_ROOT = settings.DATA_DIR / "pastes"
|
||||||
settings.PASTE_FILES_ROOT.mkdir(exist_ok=True)
|
settings.PASTE_FILES_ROOT.mkdir(exist_ok=True)
|
||||||
settings.SESSIONS_DIR = settings.VAR_DIR / "sessions"
|
|
||||||
|
settings.SESSIONS_DIR = settings.DATA_DIR / "sessions"
|
||||||
settings.SESSIONS_DIR.mkdir(exist_ok=True)
|
settings.SESSIONS_DIR.mkdir(exist_ok=True)
|
||||||
|
|
||||||
secret_key_file = settings.VAR_DIR / "secret_key"
|
bottle.TEMPLATE_PATH.insert(0, zerobin.ROOT_DIR / "views")
|
||||||
|
|
||||||
|
CUSTOM_VIEWS_DIR = settings.CONFIG_DIR / "custom_views"
|
||||||
|
CUSTOM_VIEWS_DIR.mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
bottle.TEMPLATE_PATH.insert(0, CUSTOM_VIEWS_DIR)
|
||||||
|
|
||||||
|
secret_key_file = settings.CONFIG_DIR / "secret_key"
|
||||||
if not secret_key_file.is_file():
|
if not secret_key_file.is_file():
|
||||||
secret_key_file.write_text(secrets.token_urlsafe(64))
|
secret_key_file.write_text(secrets.token_urlsafe(64))
|
||||||
settings.SECRET_KEY = secret_key_file.read_text()
|
settings.SECRET_KEY = secret_key_file.read_text()
|
||||||
|
|
||||||
admin_password_file = settings.VAR_DIR / "admin_password"
|
admin_password_file = settings.CONFIG_DIR / "admin_password"
|
||||||
if not secret_key_file.is_file():
|
if not secret_key_file.is_file():
|
||||||
admin_password_file.write_text(
|
admin_password_file.write_text(
|
||||||
"No password set. Use the set_admin_passord command. Don't write this file by hand."
|
"No password set. Use the set_admin_passord command. Don't write this file by hand."
|
||||||
@ -124,6 +150,13 @@ def ensure_var_env():
|
|||||||
payload = ("admin" + settings.SECRET_KEY).encode("ascii")
|
payload = ("admin" + settings.SECRET_KEY).encode("ascii")
|
||||||
settings.ADMIN_URL = "/admin/" + hashlib.sha256(payload).hexdigest() + "/"
|
settings.ADMIN_URL = "/admin/" + hashlib.sha256(payload).hexdigest() + "/"
|
||||||
|
|
||||||
|
settings_file = settings.CONFIG_DIR / "settings.py"
|
||||||
|
if not settings_file.is_file():
|
||||||
|
default_config = (zerobin.ROOT_DIR / "default_settings.py").read_text()
|
||||||
|
settings_file.write_text(default_config)
|
||||||
|
|
||||||
|
settings.update_with_file(settings_file)
|
||||||
|
|
||||||
|
|
||||||
def hash_password(password):
|
def hash_password(password):
|
||||||
return hashlib.scrypt(
|
return hashlib.scrypt(
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<link rel="icon" href="/static/img/favicon.ico" />
|
<link rel="icon" href="/static/img/favicon.ico" />
|
||||||
|
|
||||||
|
|
||||||
%if settings.COMPRESSED_STATIC_FILES:
|
%if not settings.DEBUG:
|
||||||
<link href="/static/css/style.min.css?{{ VERSION }}" rel="stylesheet" />
|
<link href="/static/css/style.min.css?{{ VERSION }}" rel="stylesheet" />
|
||||||
%else:
|
%else:
|
||||||
<link href="/static/css/prettify.css" rel="stylesheet" />
|
<link href="/static/css/prettify.css" rel="stylesheet" />
|
||||||
@ -94,10 +94,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script src="/static/js/vue.js"></script>
|
|
||||||
%if settings.COMPRESSED_STATIC_FILES:
|
%if not settings.DEBUG:
|
||||||
<script src="/static/js/main.min.js?{{ VERSION }}"></script>
|
<script src="/static/js/main.min.js?{{ VERSION }}"></script>
|
||||||
%else:
|
%else:
|
||||||
|
<script src="/static/js/vue.js"></script>
|
||||||
<script src="/static/js/sjcl.js"></script>
|
<script src="/static/js/sjcl.js"></script>
|
||||||
<script src="/static/js/behavior.js?{{ VERSION }}"></script>
|
<script src="/static/js/behavior.js?{{ VERSION }}"></script>
|
||||||
%end
|
%end
|
||||||
@ -107,8 +108,8 @@
|
|||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
%if settings.COMPRESSED_STATIC_FILES:
|
%if not settings.DEBUG:
|
||||||
<script src="/static/js/additional.min.js?{{ settings.VERSION }}"></script>
|
<script src="/static/js/additional.min.js?{{ VERSION }}"></script>
|
||||||
%else:
|
%else:
|
||||||
<script src="/static/js/lzw.js"></script>
|
<script src="/static/js/lzw.js"></script>
|
||||||
<script src="/static/js/prettify.min.js"></script>
|
<script src="/static/js/prettify.min.js"></script>
|
||||||
|
3
zerobin/wsgi.py
Normal file
3
zerobin/wsgi.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from zerobin.wsgi import setup_app
|
||||||
|
|
||||||
|
settings, app = get_app()
|
Loading…
x
Reference in New Issue
Block a user