diff --git a/app/blueprints/auth/__init__.py b/app/blueprints/auth/__init__.py index b64ea53b..23695dd1 100644 --- a/app/blueprints/auth/__init__.py +++ b/app/blueprints/auth/__init__.py @@ -19,6 +19,7 @@ def before_request(): and request.endpoint and request.blueprint != 'auth' and request.endpoint != 'static' + and request.endpoint != 'main.accept_terms_of_use' ): return redirect(url_for('auth.unconfirmed')) diff --git a/app/blueprints/main/routes.py b/app/blueprints/main/routes.py index 82673c91..9a69d633 100644 --- a/app/blueprints/main/routes.py +++ b/app/blueprints/main/routes.py @@ -1,8 +1,9 @@ -from flask import flash, redirect, render_template, url_for +from flask import abort, flash, jsonify, redirect, render_template, url_for from flask_login import current_user, login_required, login_user from app.blueprints.auth.forms import LoginForm from app.models import Corpus, User from . import bp +from app import db @bp.route('/', methods=['GET', 'POST']) @@ -72,6 +73,16 @@ def terms_of_use(): ) +@bp.route('/accept-terms-of-use', methods=['POST']) +@login_required +def accept_terms_of_use(): + current_user.terms_of_use_accepted = True + db.session.commit() + + return jsonify('You accepted the terms of use'), 202 + + + @bp.route('/social') @login_required def social(): diff --git a/app/blueprints/users/routes.py b/app/blueprints/users/routes.py index 3f2dec1b..5435ad25 100644 --- a/app/blueprints/users/routes.py +++ b/app/blueprints/users/routes.py @@ -132,19 +132,3 @@ def delete_user_avatar(user_id: int): thread.start() return jsonify('Avatar marked for deletion'), 202 - - -# TODO: Move this to main blueprint(?) -@bp.route('/accept-terms-of-use', methods=['POST']) -@login_required -def accept_terms_of_use(): - if not ( - current_user.is_authenticated - or current_user.confirmed - ): - abort(403) - - current_user.terms_of_use_accepted = True - db.session.commit() - - return jsonify('You accepted the terms of use'), 202 diff --git a/app/static/js/app/client.js b/app/static/js/app/client.js index faa6c264..15d39e87 100644 --- a/app/static/js/app/client.js +++ b/app/static/js/app/client.js @@ -5,6 +5,7 @@ nopaque.app.Client = class Client { // Endpoints this.corpora = new nopaque.app.endpoints.Corpora(this); this.jobs = new nopaque.app.endpoints.Jobs(this); + this.main = new nopaque.app.endpoints.Main(this); this.settings = new nopaque.app.endpoints.Settings(this); this.users = new nopaque.app.endpoints.Users(this); diff --git a/app/static/js/app/endpoints/main.js b/app/static/js/app/endpoints/main.js new file mode 100644 index 00000000..5daaa251 --- /dev/null +++ b/app/static/js/app/endpoints/main.js @@ -0,0 +1,22 @@ +nopaque.app.endpoints.Main = class Main { + constructor(app) { + this.app = app; + } + + async acceptTermsOfUse() { + const options = { + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + }, + method: 'POST', + }; + + const response = await fetch(`/accept-terms-of-use`, options); + const data = await response.json(); + + if (!response.ok) {throw new Error(`${data.name}: ${data.description}`);} + + return data; + } +} diff --git a/app/static/js/app/extensions/ui.js b/app/static/js/app/extensions/ui.js index 439d247d..4feb00c9 100644 --- a/app/static/js/app/extensions/ui.js +++ b/app/static/js/app/extensions/ui.js @@ -71,10 +71,7 @@ nopaque.app.extensions.UI = class UI { M.Modal.init( document.querySelector('#terms-of-use-modal'), { - dismissible: false, - onCloseEnd: (modalElement) => { - nopaque.requests.users.entity.acceptTermsOfUse(); - } + dismissible: false } ); // #endregion diff --git a/app/templates/_base/modals.html.j2 b/app/templates/_base/modals.html.j2 index 11559d59..9da4df70 100644 --- a/app/templates/_base/modals.html.j2 +++ b/app/templates/_base/modals.html.j2 @@ -19,12 +19,10 @@
diff --git a/app/templates/_base/scripts.html.j2 b/app/templates/_base/scripts.html.j2 index 620ae6bd..e14086a2 100644 --- a/app/templates/_base/scripts.html.j2 +++ b/app/templates/_base/scripts.html.j2 @@ -13,6 +13,7 @@ 'js/app/endpoints/index.js', 'js/app/endpoints/corpora.js', 'js/app/endpoints/jobs.js', + 'js/app/endpoints/main.js', 'js/app/endpoints/settings.js', 'js/app/endpoints/users.js', 'js/app/extensions/index.js', @@ -102,6 +103,16 @@ } {% if not current_user.terms_of_use_accepted %} + const termsOfUseAcceptButtonElement = document.querySelector('#terms-of-use-modal-accept-button'); + termsOfUseAcceptButtonElement.addEventListener('click', async () => { + try { + await app.main.acceptTermsOfUse(); + app.ui.flash('Terms of use accepted.'); + } catch (error) { + app.ui.flash('Failed to accept terms of use.', 'error'); + } + }); + const termsOfUseModalElement = document.querySelector('#terms-of-use-modal'); const termsOfUseModal = M.Modal.getInstance(termsOfUseModalElement); @@ -109,10 +120,10 @@ {% endif %} {% endif %} - const flashedMessages = {{ get_flashed_messages()|tojson }}; + const flashedMessages = {{ get_flashed_messages(with_categories=true)|tojson }}; for (let [category, message] of flashedMessages) { - app.ui.flash(message, message); + app.ui.flash(message, category); } }