diff --git a/config.example.py b/config.example.py index 53b2a40..9054e44 100644 --- a/config.example.py +++ b/config.example.py @@ -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 diff --git a/nyaa/templates/layout.html b/nyaa/templates/layout.html index 9d7feea..737847d 100644 --- a/nyaa/templates/layout.html +++ b/nyaa/templates/layout.html @@ -312,6 +312,12 @@
{% include "flashes.html" %} + {% if config.MAINTENANCE_MODE and config.MAINTENANCE_MODE_MESSAGE %} + + {% endif %} {% block body %}{% endblock %}
diff --git a/nyaa/views/__init__.py b/nyaa/views/__init__.py index ae58c99..32f745b 100644 --- a/nyaa/views/__init__.py +++ b/nyaa/views/__init__.py @@ -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) diff --git a/nyaa/views/account.py b/nyaa/views/account.py index 5e9615a..003f061 100644 --- a/nyaa/views/account.py +++ b/nyaa/views/account.py @@ -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('Logins are currently disabled.'), '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 diff --git a/nyaa/views/main.py b/nyaa/views/main.py index d9f9789..21ed75e 100644 --- a/nyaa/views/main.py +++ b/nyaa/views/main.py @@ -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': diff --git a/nyaa/views/users.py b/nyaa/views/users.py index 31b9861..48cf861 100644 --- a/nyaa/views/users.py +++ b/nyaa/views/users.py @@ -190,6 +190,10 @@ def view_user(user_name): @bp.route('/user/activate/') def activate_user(payload): + if app.config['MAINTENANCE_MODE']: + flask.flash(flask.Markup('Activations are currently disabled.'), 'danger') + return flask.redirect(flask.url_for('main.home')) + s = get_serializer() try: user_id = s.loads(payload)