diff --git a/snikket_web/templates/user_home.html b/snikket_web/templates/user_home.html index 15b7a79..faf2b68 100644 --- a/snikket_web/templates/user_home.html +++ b/snikket_web/templates/user_home.html @@ -30,6 +30,7 @@
{% call standard_button("edit", url_for(".profile"), class="primary") %}{% trans %}Edit profile{% endtrans %}{% endcall %}
{% call standard_button("passwd", url_for(".change_pw"), class="secondary") %}{% trans %}Change password{% endtrans %}{% endcall %}
+
{% call standard_button("folder", url_for(".manage_data"), class="secondary") %}{% trans %}Manage your data{% endtrans %}{% endcall %}
{#- -#} diff --git a/snikket_web/templates/user_manage_data.html b/snikket_web/templates/user_manage_data.html new file mode 100644 index 0000000..4c9dfae --- /dev/null +++ b/snikket_web/templates/user_manage_data.html @@ -0,0 +1,23 @@ +{% extends "app.html" %} +{% from "library.j2" import standard_button, form_button, render_errors, avatar with context %} +{% block content %} +

{% trans %}Manage your data{% endtrans %}

+

{% trans user_name=user_info.display_name %}Welcome home, {{ user_name }}.{% endtrans %}

+ +{% endblock %} diff --git a/snikket_web/user.py b/snikket_web/user.py index a51ec37..978ae4b 100644 --- a/snikket_web/user.py +++ b/snikket_web/user.py @@ -1,9 +1,12 @@ +import aiohttp import asyncio import typing +import urllib import quart.flask_patch from quart import ( Blueprint, + Response, render_template, request, redirect, @@ -168,6 +171,50 @@ async def profile() -> typing.Union[str, quart.Response]: avatar_too_big_warning=EAVATARTOOBIG) +class DataExportForm(BaseForm): + action_export = wtforms.SubmitField( + _l("Export") + ) + + +@bp.route("/manage_data", methods=["GET", "POST"]) +@client.require_session() +async def manage_data() -> typing.Union[str, quart.Response]: + form = DataExportForm() + + if form.validate_on_submit(): + user_info = await client.get_user_info() + # The UTF-8 version of the filename needs to be percent-encoded + encoded_address = urllib.parse.quote( + user_info["address"].encode(encoding='utf-8', errors='strict') + ) + try: + account_data = await client.export_account_data() + except aiohttp.ClientResponseError as e: + if e.status == 404: + await flash( + _("You currently have no account data to export."), + "alert" + ) + else: + raise e + else: + return Response(account_data, + mimetype="application/xml", + headers={ + # We provide the UTF-8 filename, but the ASCII + # one will be used as a fallback for legacy + # browsers (RFC 5987) + "Content-Disposition": ( + 'attachment; filename="account-data.xml"; ' + 'filename*="UTF-8\'\'account-data-{}.xml"' + ).format(encoded_address) + }) + return await render_template("user_manage_data.html", + form=form, + ) + + @bp.route("/logout", methods=["GET", "POST"]) @client.require_session() async def logout() -> typing.Union[quart.Response, str]: