forked from rDrama/rDrama
fdMerge branch 'frost' of https://github.com/Aevann1/Drama into frost
commit
059e9ff6b1
|
@ -0,0 +1 @@
|
||||||
|
* @Aevann1
|
|
@ -6,20 +6,18 @@ from flask import *
|
||||||
from flask_caching import Cache
|
from flask_caching import Cache
|
||||||
from flask_limiter import Limiter
|
from flask_limiter import Limiter
|
||||||
from flask_compress import Compress
|
from flask_compress import Compress
|
||||||
from flask_limiter.util import get_ipaddr
|
|
||||||
from flask_mail import Mail
|
from flask_mail import Mail
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||||
from sqlalchemy import *
|
from sqlalchemy import *
|
||||||
import gevent
|
import gevent
|
||||||
from werkzeug.middleware.proxy_fix import ProxyFix
|
|
||||||
import redis
|
import redis
|
||||||
import time
|
import time
|
||||||
from sys import stdout
|
from sys import stdout
|
||||||
import faulthandler
|
import faulthandler
|
||||||
|
from json import loads
|
||||||
|
|
||||||
app = Flask(__name__, template_folder='templates')
|
app = Flask(__name__, template_folder='templates')
|
||||||
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=3)
|
|
||||||
app.url_map.strict_slashes = False
|
app.url_map.strict_slashes = False
|
||||||
app.jinja_env.cache = {}
|
app.jinja_env.cache = {}
|
||||||
app.jinja_env.auto_reload = True
|
app.jinja_env.auto_reload = True
|
||||||
|
@ -63,9 +61,13 @@ app.config['DESCRIPTION'] = environ.get("DESCRIPTION", "rdrama.net caters to dra
|
||||||
|
|
||||||
r=redis.Redis(host=environ.get("REDIS_URL", "redis://localhost"), decode_responses=True, ssl_cert_reqs=None)
|
r=redis.Redis(host=environ.get("REDIS_URL", "redis://localhost"), decode_responses=True, ssl_cert_reqs=None)
|
||||||
|
|
||||||
|
def get_CF() -> str:
|
||||||
|
with app.app_context():
|
||||||
|
return request.headers.get('CF-Connecting-IP')
|
||||||
|
|
||||||
limiter = Limiter(
|
limiter = Limiter(
|
||||||
app,
|
app,
|
||||||
key_func=get_ipaddr,
|
key_func=get_CF,
|
||||||
default_limits=["3/second;30/minute;200/hour;1000/day"],
|
default_limits=["3/second;30/minute;200/hour;1000/day"],
|
||||||
application_limits=["10/second;200/minute;5000/hour;10000/day"],
|
application_limits=["10/second;200/minute;5000/hour;10000/day"],
|
||||||
storage_uri=environ.get("REDIS_URL", "redis://localhost")
|
storage_uri=environ.get("REDIS_URL", "redis://localhost")
|
||||||
|
@ -83,7 +85,6 @@ mail = Mail(app)
|
||||||
|
|
||||||
@app.before_request
|
@app.before_request
|
||||||
def before_request():
|
def before_request():
|
||||||
|
|
||||||
if request.method.lower() != "get" and app.config["READ_ONLY"]:
|
if request.method.lower() != "get" and app.config["READ_ONLY"]:
|
||||||
return {"error":f"{app.config['SITE_NAME']} is currently in read-only mode."}, 500
|
return {"error":f"{app.config['SITE_NAME']} is currently in read-only mode."}, 500
|
||||||
|
|
||||||
|
@ -104,9 +105,10 @@ def teardown_request(error):
|
||||||
|
|
||||||
@app.after_request
|
@app.after_request
|
||||||
def after_request(response):
|
def after_request(response):
|
||||||
|
|
||||||
response.headers.add("Strict-Transport-Security", "max-age=31536000")
|
response.headers.add("Strict-Transport-Security", "max-age=31536000")
|
||||||
response.headers.add("X-Frame-Options", "deny")
|
response.headers.add("X-Frame-Options", "deny")
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
with open("marsey_count.json", 'r') as f: cache.set("marsey_count", loads(f.read()))
|
||||||
|
|
||||||
from files.routes import *
|
from files.routes import *
|
|
@ -315,7 +315,7 @@ class User(Base):
|
||||||
return f"/@{self.username}"
|
return f"/@{self.username}"
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<User(username={self.username})>"
|
return f"<User(id={self.id})>"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@lazy
|
@lazy
|
||||||
|
|
|
@ -477,6 +477,10 @@ BADGES = {
|
||||||
'name': 'Benefactor',
|
'name': 'Benefactor',
|
||||||
'description': 'Gave the Benefactor award to someone'
|
'description': 'Gave the Benefactor award to someone'
|
||||||
},
|
},
|
||||||
|
104: {
|
||||||
|
'name': 'BADASS OUTLAW',
|
||||||
|
'description': 'Bad boy who does not play by the rules'
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
AWARDS = {
|
AWARDS = {
|
||||||
|
|
|
@ -178,7 +178,7 @@ def sanitize(sanitized, noimages=False, alert=False, comment=False, edit=False):
|
||||||
sanitized = re.sub('\|\|(.*?)\|\|', r'<span class="spoiler">\1</span>', sanitized)
|
sanitized = re.sub('\|\|(.*?)\|\|', r'<span class="spoiler">\1</span>', sanitized)
|
||||||
|
|
||||||
if comment:
|
if comment:
|
||||||
with open("marsey_count.json", 'r') as f: marsey_count = loads(f.read())
|
marsey_count = cache.get("marsey_count")
|
||||||
marseys_used = set()
|
marseys_used = set()
|
||||||
|
|
||||||
for i in re.finditer("[^a]>\s*(:[!#]{0,2}\w+:\s*)+<\/", sanitized):
|
for i in re.finditer("[^a]>\s*(:[!#]{0,2}\w+:\s*)+<\/", sanitized):
|
||||||
|
@ -260,7 +260,7 @@ def sanitize(sanitized, noimages=False, alert=False, comment=False, edit=False):
|
||||||
if comment:
|
if comment:
|
||||||
for emoji in marseys_used:
|
for emoji in marseys_used:
|
||||||
if emoji in marsey_count: marsey_count[emoji] += 1
|
if emoji in marsey_count: marsey_count[emoji] += 1
|
||||||
with open('marsey_count.json', 'w') as f: dump(marsey_count, f)
|
cache.set("marsey_count", marsey_count)
|
||||||
|
|
||||||
return sanitized
|
return sanitized
|
||||||
|
|
||||||
|
|
|
@ -1170,7 +1170,7 @@ def api_unban_comment(c_id, v):
|
||||||
comment = g.db.query(Comment).filter_by(id=c_id).one_or_none()
|
comment = g.db.query(Comment).filter_by(id=c_id).one_or_none()
|
||||||
if not comment: abort(404)
|
if not comment: abort(404)
|
||||||
|
|
||||||
if comment.author.agendaposter and 'black lives matters' not in comment.body.lower():
|
if comment.author.agendaposter and AGENDAPOSTER_PHRASE not in comment.body.lower():
|
||||||
return {"error": "You can't bypass the agendaposter award!"}
|
return {"error": "You can't bypass the agendaposter award!"}
|
||||||
|
|
||||||
if comment.is_banned:
|
if comment.is_banned:
|
||||||
|
@ -1211,6 +1211,7 @@ def admin_distinguish_comment(c_id, v):
|
||||||
@app.get("/admin/dump_cache")
|
@app.get("/admin/dump_cache")
|
||||||
@admin_level_required(2)
|
@admin_level_required(2)
|
||||||
def admin_dump_cache(v):
|
def admin_dump_cache(v):
|
||||||
|
with open('marsey_count.json', 'w') as f: dump(cache.get("marsey_count"), f)
|
||||||
cache.clear()
|
cache.clear()
|
||||||
return {"message": "Internal cache cleared."}
|
return {"message": "Internal cache cleared."}
|
||||||
|
|
||||||
|
|
|
@ -481,7 +481,7 @@ def api_comment(v):
|
||||||
'body': notifbody,
|
'body': notifbody,
|
||||||
},
|
},
|
||||||
'data': {
|
'data': {
|
||||||
'url': f'comment/{c.id}?context=9&read=true#context',
|
'url': f'/comment/{c.id}?context=9&read=true#context',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -396,6 +396,8 @@ def get_reset():
|
||||||
|
|
||||||
user = g.db.query(User).filter_by(id=user_id).one_or_none()
|
user = g.db.query(User).filter_by(id=user_id).one_or_none()
|
||||||
|
|
||||||
|
if not user: abort(400)
|
||||||
|
|
||||||
if not validate_hash(f"{user_id}+{timestamp}+forgot+{user.login_nonce}", token):
|
if not validate_hash(f"{user_id}+{timestamp}+forgot+{user.login_nonce}", token):
|
||||||
abort(400)
|
abort(400)
|
||||||
|
|
||||||
|
|
|
@ -857,7 +857,7 @@ def settings_name_change(v):
|
||||||
v=v,
|
v=v,
|
||||||
error=f"Username `{new_name}` is already in use.")
|
error=f"Username `{new_name}` is already in use.")
|
||||||
|
|
||||||
v=g.db.query(User).with_for_update().filter_by(id=v.id).one_or_none()
|
v=g.db.query(User).filter_by(id=v.id).one_or_none()
|
||||||
|
|
||||||
v.username=new_name
|
v.username=new_name
|
||||||
v.name_changed_utc=int(time.time())
|
v.name_changed_utc=int(time.time())
|
||||||
|
@ -876,7 +876,8 @@ def settings_name_change(v):
|
||||||
def settings_song_change(v):
|
def settings_song_change(v):
|
||||||
song=request.values.get("song").strip()
|
song=request.values.get("song").strip()
|
||||||
|
|
||||||
if song == "" and v.song and path.isfile(f"/songs/{v.song}.mp3") and g.db.query(User.id).filter_by(song=v.song).count() == 1:
|
if song == "" and v.song:
|
||||||
|
if path.isfile(f"/songs/{v.song}.mp3") and g.db.query(User.id).filter_by(song=v.song).count() == 1:
|
||||||
os.remove(f"/songs/{v.song}.mp3")
|
os.remove(f"/songs/{v.song}.mp3")
|
||||||
v.song = None
|
v.song = None
|
||||||
g.db.add(v)
|
g.db.add(v)
|
||||||
|
|
|
@ -17,8 +17,7 @@ def privacy(v):
|
||||||
@app.get("/marseys")
|
@app.get("/marseys")
|
||||||
@auth_required
|
@auth_required
|
||||||
def emojis(v):
|
def emojis(v):
|
||||||
with open("marsey_count.json", 'r') as file:
|
marsey_count = cache.get("marsey_count")
|
||||||
marsey_count = loads(file.read())
|
|
||||||
marsey_counted = []
|
marsey_counted = []
|
||||||
for k, val in marseys.items():
|
for k, val in marseys.items():
|
||||||
marsey_counted.append((k, val, marsey_count[k]))
|
marsey_counted.append((k, val, marsey_count[k]))
|
||||||
|
|
|
@ -503,7 +503,7 @@ def message2(v, username):
|
||||||
'body': notifbody,
|
'body': notifbody,
|
||||||
},
|
},
|
||||||
'data': {
|
'data': {
|
||||||
'url': 'notifications?messages=true',
|
'url': '/notifications?messages=true',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -570,7 +570,7 @@ def messagereply(v):
|
||||||
'body': notifbody,
|
'body': notifbody,
|
||||||
},
|
},
|
||||||
'data': {
|
'data': {
|
||||||
'url': 'notifications?messages=true',
|
'url': '/notifications?messages=true',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
{% if v %}
|
{% if v %}
|
||||||
<style>:root{--primary:#{{v.themecolor}}}</style>
|
<style>:root{--primary:#{{v.themecolor}}}</style>
|
||||||
<link rel="stylesheet" href="/static/assets/css/main.css?a=92"><link rel="stylesheet" href="/static/assets/css/{{v.theme}}.css?a=13">
|
<link rel="stylesheet" href="/static/assets/css/main.css?a=93"><link rel="stylesheet" href="/static/assets/css/{{v.theme}}.css?a=14">
|
||||||
{% if v.agendaposter %}
|
{% if v.agendaposter %}
|
||||||
<style>
|
<style>
|
||||||
html {
|
html {
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
|
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
|
||||||
<link rel="stylesheet" href="/static/assets/css/main.css?a=92"><link rel="stylesheet" href="/static/assets/css/{{'DEFAULT_THEME' | app_config}}.css?a=13">
|
<link rel="stylesheet" href="/static/assets/css/main.css?a=93"><link rel="stylesheet" href="/static/assets/css/{{'DEFAULT_THEME' | app_config}}.css?a=14">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
<script src="/static/assets/js/bootstrap.js?a=202"></script>
|
<script src="/static/assets/js/bootstrap.js?a=202"></script>
|
||||||
{% if v %}
|
{% if v %}
|
||||||
<style>:root{--primary:#{{v.themecolor}}}</style>
|
<style>:root{--primary:#{{v.themecolor}}}</style>
|
||||||
<link rel="stylesheet" href="/static/assets/css/main.css?a=92">
|
<link rel="stylesheet" href="/static/assets/css/main.css?a=93">
|
||||||
<link rel="stylesheet" href="/static/assets/css/{{v.theme}}.css?a=13">
|
<link rel="stylesheet" href="/static/assets/css/{{v.theme}}.css?a=14">
|
||||||
{% if v.agendaposter %}
|
{% if v.agendaposter %}
|
||||||
<style>
|
<style>
|
||||||
html {
|
html {
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
|
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
|
||||||
<link rel="stylesheet" href="/static/assets/css/main.css?a=92"><link rel="stylesheet" href="/static/assets/css/{{'DEFAULT_THEME' | app_config}}.css?a=13">
|
<link rel="stylesheet" href="/static/assets/css/main.css?a=93"><link rel="stylesheet" href="/static/assets/css/{{'DEFAULT_THEME' | app_config}}.css?a=14">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% if v %}
|
{% if v %}
|
||||||
<style>:root{--primary:#{{v.themecolor}}}</style>
|
<style>:root{--primary:#{{v.themecolor}}}</style>
|
||||||
<link rel="stylesheet" href="/static/assets/css/main.css?a=92"><link rel="stylesheet" href="/static/assets/css/{{v.theme}}.css?a=13">
|
<link rel="stylesheet" href="/static/assets/css/main.css?a=93"><link rel="stylesheet" href="/static/assets/css/{{v.theme}}.css?a=14">
|
||||||
{% if v.agendaposter %}
|
{% if v.agendaposter %}
|
||||||
<style>
|
<style>
|
||||||
html {
|
html {
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
|
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
|
||||||
<link rel="stylesheet" href="/static/assets/css/main.css?a=92"><link rel="stylesheet" href="/static/assets/css/{{'DEFAULT_THEME' | app_config}}.css?a=13">
|
<link rel="stylesheet" href="/static/assets/css/main.css?a=93"><link rel="stylesheet" href="/static/assets/css/{{'DEFAULT_THEME' | app_config}}.css?a=14">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="row justify-content-around">
|
<div class="row justify-content-around">
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
|
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
|
||||||
<link rel="stylesheet" href="/static/assets/css/main.css?a=92">
|
<link rel="stylesheet" href="/static/assets/css/main.css?a=93">
|
||||||
<link rel="stylesheet" href="/static/assets/css/{{'DEFAULT_THEME' | app_config}}.css?a=13">
|
<link rel="stylesheet" href="/static/assets/css/{{'DEFAULT_THEME' | app_config}}.css?a=14">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<title>2-Step Login - {{SITE_NAME}}</title>
|
<title>2-Step Login - {{SITE_NAME}}</title>
|
||||||
|
|
||||||
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
|
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
|
||||||
<link rel="stylesheet" href="/static/assets/css/main.css?a=92"><link rel="stylesheet" href="/static/assets/css/{{'DEFAULT_THEME' | app_config}}.css?a=13">
|
<link rel="stylesheet" href="/static/assets/css/main.css?a=93"><link rel="stylesheet" href="/static/assets/css/{{'DEFAULT_THEME' | app_config}}.css?a=14">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
|
|
||||||
<style>:root{--primary:#{{v.themecolor}}}</style>
|
<style>:root{--primary:#{{v.themecolor}}}</style>
|
||||||
<link rel="stylesheet" href="/static/assets/css/main.css?a=92"><link rel="stylesheet" href="/static/assets/css/{{v.theme}}.css?a=13">
|
<link rel="stylesheet" href="/static/assets/css/main.css?a=93"><link rel="stylesheet" href="/static/assets/css/{{v.theme}}.css?a=14">
|
||||||
{% if v.agendaposter %}
|
{% if v.agendaposter %}
|
||||||
<style>
|
<style>
|
||||||
html {
|
html {
|
||||||
|
|
|
@ -39,10 +39,10 @@
|
||||||
|
|
||||||
{% if v %}
|
{% if v %}
|
||||||
<style>:root{--primary:#{{v.themecolor}}}</style>
|
<style>:root{--primary:#{{v.themecolor}}}</style>
|
||||||
<link rel="stylesheet" href="/static/assets/css/main.css?a=92"><link rel="stylesheet" href="/static/assets/css/{{v.theme}}.css?a=13">
|
<link rel="stylesheet" href="/static/assets/css/main.css?a=93"><link rel="stylesheet" href="/static/assets/css/{{v.theme}}.css?a=14">
|
||||||
{% else %}
|
{% else %}
|
||||||
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
|
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
|
||||||
<link rel="stylesheet" href="/static/assets/css/main.css?a=92"><link rel="stylesheet" href="/static/assets/css/{{'DEFAULT_THEME' | app_config}}.css?a=13">
|
<link rel="stylesheet" href="/static/assets/css/main.css?a=93"><link rel="stylesheet" href="/static/assets/css/{{'DEFAULT_THEME' | app_config}}.css?a=14">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
<title>{% if ref_user %}{{ref_user.username}} invites you to {{SITE_NAME}}{% else %}Sign up - {{SITE_NAME}}{% endif %}</title>
|
<title>{% if ref_user %}{{ref_user.username}} invites you to {{SITE_NAME}}{% else %}Sign up - {{SITE_NAME}}{% endif %}</title>
|
||||||
|
|
||||||
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
|
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
|
||||||
<link rel="stylesheet" href="/static/assets/css/main.css?a=92"><link rel="stylesheet" href="/static/assets/css/{{'DEFAULT_THEME' | app_config}}.css?a=13">
|
<link rel="stylesheet" href="/static/assets/css/main.css?a=93"><link rel="stylesheet" href="/static/assets/css/{{'DEFAULT_THEME' | app_config}}.css?a=14">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
<title>{% if ref_user %}{{ref_user.username}} invites you to {{SITE_NAME}}{% else %}{{SITE_NAME}}{% endif %}</title>
|
<title>{% if ref_user %}{{ref_user.username}} invites you to {{SITE_NAME}}{% else %}{{SITE_NAME}}{% endif %}</title>
|
||||||
|
|
||||||
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
|
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
|
||||||
<link rel="stylesheet" href="/static/assets/css/main.css?a=92"><link rel="stylesheet" href="/static/assets/css/{{'DEFAULT_THEME' | app_config}}.css?a=13">
|
<link rel="stylesheet" href="/static/assets/css/main.css?a=93"><link rel="stylesheet" href="/static/assets/css/{{'DEFAULT_THEME' | app_config}}.css?a=14">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
{% block stylesheets %}
|
{% block stylesheets %}
|
||||||
{% if v %}
|
{% if v %}
|
||||||
<style>:root{--primary:#{{v.themecolor}}}</style>
|
<style>:root{--primary:#{{v.themecolor}}}</style>
|
||||||
<link rel="stylesheet" href="/static/assets/css/main.css?a=92"><link rel="stylesheet" href="/static/assets/css/{{v.theme}}.css?a=13">
|
<link rel="stylesheet" href="/static/assets/css/main.css?a=93"><link rel="stylesheet" href="/static/assets/css/{{v.theme}}.css?a=14">
|
||||||
{% if v.agendaposter %}
|
{% if v.agendaposter %}
|
||||||
<style>
|
<style>
|
||||||
html {
|
html {
|
||||||
|
@ -50,8 +50,8 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
|
<style>:root{--primary:#{{'DEFAULT_COLOR' | app_config}}</style>
|
||||||
<link rel="stylesheet" href="/static/assets/css/main.css?a=92">
|
<link rel="stylesheet" href="/static/assets/css/main.css?a=93">
|
||||||
<link rel="stylesheet" href="/static/assets/css/{{'DEFAULT_THEME' | app_config}}.css?a=13">
|
<link rel="stylesheet" href="/static/assets/css/{{'DEFAULT_THEME' | app_config}}.css?a=14">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,12 @@ bleach
|
||||||
Flask
|
Flask
|
||||||
Flask-Caching
|
Flask-Caching
|
||||||
Flask-Compress
|
Flask-Compress
|
||||||
Flask-Limiter==1.1.0
|
Flask-Limiter
|
||||||
Flask-Mail==0.9.1
|
Flask-Mail
|
||||||
gevent
|
gevent
|
||||||
greenlet
|
greenlet
|
||||||
gunicorn
|
gunicorn
|
||||||
markdown
|
mistletoe
|
||||||
matplotlib
|
matplotlib
|
||||||
Pillow
|
Pillow
|
||||||
psutil
|
psutil
|
||||||
|
|
Loading…
Reference in New Issue