Read-only maintenance mode setting for config.py (#356)

Disables all POSTs, optionally allowing users to log in (without updating last login date)
Blocked POSTs will redirect to the GET endpoint if possible, otherwise to referrer or in last case, home page.
API requests will get a plaintext message with 405 status code.
This commit is contained in:
Anna-Maria Meriniemi 2017-09-05 01:16:52 +03:00 committed by Arylide
parent 5e93d7ec6d
commit c5d705210d
6 changed files with 61 additions and 8 deletions

View File

@ -1,7 +1,13 @@
import os
DEBUG = True
# A read-only maintenance mode, in which the database is not modified
MAINTENANCE_MODE = True
# A maintenance message (used in layout.html template)
MAINTENANCE_MODE_MESSAGE = 'Site is currently in read-only maintenance mode.'
# Allow logging in during maintenance (without updating last login date)
MAINTENANCE_MODE_LOGINS = True
USE_RECAPTCHA = False
USE_EMAIL_VERIFICATION = False
USE_MYSQL = True

View File

@ -312,6 +312,12 @@
<div class="container">
{% include "flashes.html" %}
{% if config.MAINTENANCE_MODE and config.MAINTENANCE_MODE_MESSAGE %}
<div class="alert alert-dismissable alert-warning" role="alert">
<button type="button" class="close" data-dismiss="alert">&times;</button>
{{ config.MAINTENANCE_MODE_MESSAGE | safe }}
</div>
{% endif %}
{% block body %}{% endblock %}
</div> <!-- /container -->

View File

@ -1,3 +1,5 @@
import flask
from nyaa.views import ( # isort:skip
account,
admin,
@ -8,8 +10,37 @@ from nyaa.views import ( # isort:skip
)
def _maintenance_mode_hook():
''' Blocks POSTs, unless MAINTENANCE_MODE_LOGINS is True and the POST is for a login. '''
if flask.request.method == 'POST':
allow_logins = flask.current_app.config['MAINTENANCE_MODE_LOGINS']
endpoint = flask.request.endpoint
if not (allow_logins and endpoint == 'account.login'):
message = 'Site is currently in maintenance mode.'
# In case of an API request, return a plaintext error message
if endpoint.startswith('api.'):
resp = flask.make_response(message, 405)
resp.headers['Content-Type'] = 'text/plain'
return resp
else:
# Otherwise redirect to the target page and flash a message
flask.flash(flask.Markup(message), 'danger')
try:
target_url = flask.url_for(endpoint)
except:
# Non-GET-able endpoint, try referrer or default to home page
target_url = flask.request.referrer or flask.url_for('main.home')
return flask.redirect(target_url)
def register_views(flask_app):
""" Register the blueprints using the flask_app object """
# Add our POST blocker first
if flask_app.config['MAINTENANCE_MODE']:
flask_app.before_request(_maintenance_mode_hook)
flask_app.register_blueprint(account.bp)
flask_app.register_blueprint(admin.bp)
flask_app.register_blueprint(main.bp)

View File

@ -21,6 +21,10 @@ def login():
form = forms.LoginForm(flask.request.form)
if flask.request.method == 'POST' and form.validate():
if app.config['MAINTENANCE_MODE'] and not app.config['MAINTENANCE_MODE_LOGINS']:
flask.flash(flask.Markup('<strong>Logins are currently disabled.</strong>'), 'danger')
return flask.redirect(flask.url_for('account.login'))
username = form.username.data.strip()
password = form.password.data
user = models.User.by_username(username)
@ -40,8 +44,9 @@ def login():
user.last_login_date = datetime.utcnow()
user.last_login_ip = ip_address(flask.request.remote_addr).packed
db.session.add(user)
db.session.commit()
if not app.config['MAINTENANCE_MODE']:
db.session.add(user)
db.session.commit()
flask.g.user = user
flask.session['user_id'] = user.id

View File

@ -41,11 +41,12 @@ def before_request():
flask.session.permanent = True
flask.session.modified = True
ip = ip_address(flask.request.remote_addr)
if user.last_login_ip != ip:
user.last_login_ip = ip.packed
db.session.add(user)
db.session.commit()
if not app.config['MAINTENANCE_MODE']:
ip = ip_address(flask.request.remote_addr)
if user.last_login_ip != ip:
user.last_login_ip = ip.packed
db.session.add(user)
db.session.commit()
# Check if user is banned on POST
if flask.request.method == 'POST':

View File

@ -190,6 +190,10 @@ def view_user(user_name):
@bp.route('/user/activate/<payload>')
def activate_user(payload):
if app.config['MAINTENANCE_MODE']:
flask.flash(flask.Markup('<strong>Activations are currently disabled.</strong>'), 'danger')
return flask.redirect(flask.url_for('main.home'))
s = get_serializer()
try:
user_id = s.loads(payload)