~homeworkprod/byceps

4a0798fa5bbfad3e613040b59f5b42d068da5ccd — Jochen Kupperschmidt 1 year, 30 days ago 3f9c69c
Extract current user settings into separate blueprint
18 files changed, 173 insertions(+), 157 deletions(-)

M byceps/blueprints/admin/core/templates/layout/admin/_current_user.html
M byceps/blueprints/blueprints.py
M byceps/blueprints/common/authentication/password/templates/common/authentication/password/update_form.html
M byceps/blueprints/common/core/templates/layout/_current_user.html
M byceps/blueprints/common/core/templates/layout/_current_user_menu_items.html
M byceps/blueprints/common/user/avatar/views.py
M byceps/blueprints/common/user/current/views.py
A byceps/blueprints/common/user/settings/__init__.py
R byceps/blueprints/common/user/{current/forms.py => settings/forms.py}
R byceps/blueprints/common/user/{current/templates/common/user/current/_account.html => settings/templates/common/user/settings/_account.html}
R byceps/blueprints/common/user/{current/templates/common/user/current/_details_personal.html => settings/templates/common/user/settings/_details_personal.html}
R byceps/blueprints/common/user/{current/templates/common/user/current/_newsletter.html => settings/templates/common/user/settings/_newsletter.html}
R byceps/blueprints/common/user/{current/templates/common/user/current/change_screen_name_form.html => settings/templates/common/user/settings/change_screen_name_form.html}
R byceps/blueprints/common/user/{current/templates/common/user/current/details_update_form.html => settings/templates/common/user/settings/details_update_form.html}
R byceps/blueprints/common/user/{current/templates/common/user/current/view.html => settings/templates/common/user/settings/view.html}
A byceps/blueprints/common/user/settings/views.py
A tests/integration/blueprints/common/user/settings/__init__.py
R tests/integration/blueprints/common/user/{test_current_user_settings.py => settings/test_views.py}
M byceps/blueprints/admin/core/templates/layout/admin/_current_user.html => byceps/blueprints/admin/core/templates/layout/admin/_current_user.html +2 -2
@@ 6,7 6,7 @@
<div class="current-user">
  {%- if g.current_user.is_active %}
  <div class="dropdown left">
    <button href="{{ url_for('user_current.view') }}" class="dropdown-toggle button button--clear">
    <button href="{{ url_for('user_settings.view') }}" class="dropdown-toggle button button--clear">
      {{ render_user_avatar_32(g.current_user) }}
      {{ render_icon('caret-down') }}
    </button>


@@ 19,7 19,7 @@
      </li>
      <li class="divider"></li>
      <li><a href="{{ url_for('user_admin.view', user_id=g.current_user.id) }}">{{ render_icon('user-profile') }} Profil</a></li>
      <li><a href="{{ url_for('user_current.view') }}">{{ render_icon('user') }} Einstellungen</a></li>
      <li><a href="{{ url_for('user_settings.view') }}">{{ render_icon('user') }} Einstellungen</a></li>
      <li class="divider"></li>
      <li><a data-action="logout" href="{{ url_for('authentication.logout', _method='POST') }}">{{ render_icon('log-out') }} abmelden</a></li>
    </ol>

M byceps/blueprints/blueprints.py => byceps/blueprints/blueprints.py +1 -0
@@ 52,6 52,7 @@ def _get_blueprints_common() -> Iterator[BlueprintReg]:
        ('common.user.creation',            '/users'                    ),
        ('common.user.current',             '/users'                    ),
        ('common.user.email_address',       '/users/email_address'      ),
        ('common.user.settings',            '/users/me/settings'        ),
    ]



M byceps/blueprints/common/authentication/password/templates/common/authentication/password/update_form.html => byceps/blueprints/common/authentication/password/templates/common/authentication/password/update_form.html +1 -1
@@ 15,7 15,7 @@
      {{ form_field(form.new_password_confirmation, maxlength=100, required='required') }}
    {%- endcall %}

    {{ form_buttons('Passwort ändern', cancel_url=url_for('user_current.view')) }}
    {{ form_buttons('Passwort ändern', cancel_url=url_for('user_settings.view')) }}
  </form>

{%- endblock %}

M byceps/blueprints/common/core/templates/layout/_current_user.html => byceps/blueprints/common/core/templates/layout/_current_user.html +1 -1
@@ 6,7 6,7 @@
<div class="current-user">
  {%- if g.current_user.is_active %}
  <div class="dropdown left">
    <a href="{{ url_for('user_current.view') }}" class="dropdown-toggle">
    <a href="{{ url_for('user_settings.view') }}" class="dropdown-toggle">
      {{ render_user_avatar_32(g.current_user) }}
      <span class="label-and-name">
        <span class="label">Angemeldet als</span>

M byceps/blueprints/common/core/templates/layout/_current_user_menu_items.html => byceps/blueprints/common/core/templates/layout/_current_user_menu_items.html +1 -1
@@ 2,6 2,6 @@


      <li><a href="{{ url_for('user_profile.view', user_id=g.current_user.id) }}">{{ render_icon('user-profile') }} Profil</a></li>
      <li><a href="{{ url_for('user_current.view') }}">{{ render_icon('user') }} Einstellungen</a></li>
      <li><a href="{{ url_for('user_settings.view') }}">{{ render_icon('user') }} Einstellungen</a></li>
      <li><a href="{{ url_for('ticketing.index_mine') }}">{{ render_icon('ticket') }} Tickets</a></li>
      <li><a href="{{ url_for('shop_orders.index') }}">{{ render_icon('invoice') }} Bestellungen</a></li>

M byceps/blueprints/common/user/avatar/views.py => byceps/blueprints/common/user/avatar/views.py +1 -1
@@ 69,7 69,7 @@ def update():
    flash_success('Dein Avatarbild wurde aktualisiert.', icon='upload')
    user_avatar_signals.avatar_updated.send(None, user_id=user.id)

    return redirect_to('user_current.view')
    return redirect_to('user_settings.view')


def _update(user_id, image):

M byceps/blueprints/common/user/current/views.py => byceps/blueprints/common/user/current/views.py +1 -146
@@ 6,60 6,15 @@ byceps.blueprints.common.user.current.views
:License: Modified BSD, see LICENSE for details.
"""

from flask import abort, g, jsonify, request, Response
from flask import abort, g, jsonify, Response

from .....config import get_app_mode
from .....services.country import service as country_service
from .....services.newsletter import service as newsletter_service
from .....services.user import command_service as user_command_service
from .....services.user import service as user_service
from .....signals import user as user_signals
from .....util.framework.blueprint import create_blueprint
from .....util.framework.flash import flash_success
from .....util.framework.templating import templated
from .....util.views import redirect_to

from ...authentication.decorators import login_required

from ..creation.views import _find_newsletter_list_for_brand

from .forms import DetailsForm, ChangeScreenNameForm


blueprint = create_blueprint('user_current', __name__)


@blueprint.route('/me/settings')
@login_required
@templated
def view():
    """Show the current user's internal profile."""
    current_user = g.current_user

    user = user_service.find_active_db_user(current_user.id)
    if user is None:
        abort(404)

    if get_app_mode().is_site():
        newsletter_list_id = _find_newsletter_list_for_brand()
        newsletter_offered = newsletter_list_id is not None

        subscribed_to_newsletter = newsletter_service.is_subscribed(
            user.id, newsletter_list_id
        )
    else:
        newsletter_list_id = None
        newsletter_offered = False
        subscribed_to_newsletter = None

    return {
        'user': user,
        'newsletter_offered': newsletter_offered,
        'newsletter_list_id': newsletter_list_id,
        'subscribed_to_newsletter': subscribed_to_newsletter,
    }


@blueprint.route('/me.json')
def view_as_json():
    """Show selected attributes of the current user's profile as JSON."""


@@ 79,103 34,3 @@ def view_as_json():
            'avatar_url': user.avatar_url,
        }
    )


@blueprint.route('/me/settings/screen_name')
@templated
def change_screen_name_form(erroneous_form=None):
    """Show a form to change the current user's screen name."""
    _get_current_user_or_404()

    form = erroneous_form if erroneous_form else ChangeScreenNameForm()

    return {
        'form': form,
    }


@blueprint.route('/me/settings/screen_name', methods=['POST'])
def change_screen_name():
    """Change the current user's screen name."""
    current_user = _get_current_user_or_404()

    form = ChangeScreenNameForm(request.form)
    if not form.validate():
        return change_screen_name_form(form)

    old_screen_name = current_user.screen_name
    new_screen_name = form.screen_name.data.strip()
    initiator_id = current_user.id

    event = user_command_service.change_screen_name(
        current_user.id, new_screen_name, initiator_id
    )

    user_signals.screen_name_changed.send(None, event=event)

    flash_success(f'Dein Benutzername wurde zu "{new_screen_name}" geändert.')

    return redirect_to('.view')


@blueprint.route('/me/settings/details')
@templated
def details_update_form(erroneous_form=None):
    """Show a form to update the current user's details."""
    current_user = _get_current_user_or_404()
    user = user_service.find_user_with_details(current_user.id)

    form = erroneous_form if erroneous_form else DetailsForm(obj=user.detail)
    country_names = country_service.get_country_names()

    return {
        'form': form,
        'country_names': country_names,
    }


@blueprint.route('/me/settings/details', methods=['POST'])
def details_update():
    """Update the current user's details."""
    current_user = _get_current_user_or_404()

    form = DetailsForm(request.form)

    if not form.validate():
        return details_update_form(form)

    first_names = form.first_names.data.strip()
    last_name = form.last_name.data.strip()
    date_of_birth = form.date_of_birth.data
    country = form.country.data.strip()
    zip_code = form.zip_code.data.strip()
    city = form.city.data.strip()
    street = form.street.data.strip()
    phone_number = form.phone_number.data.strip()

    event = user_command_service.update_user_details(
        current_user.id,
        first_names,
        last_name,
        date_of_birth,
        country,
        zip_code,
        city,
        street,
        phone_number,
        current_user.id,  # initiator_id
    )

    flash_success('Deine Daten wurden gespeichert.')

    user_signals.details_updated.send(None, event=event)

    return redirect_to('.view')


def _get_current_user_or_404():
    user = g.current_user
    if not user.is_active:
        abort(404)

    return user

A byceps/blueprints/common/user/settings/__init__.py => byceps/blueprints/common/user/settings/__init__.py +0 -0
R byceps/blueprints/common/user/current/forms.py => byceps/blueprints/common/user/settings/forms.py +2 -2
@@ 1,6 1,6 @@
"""
byceps.blueprints.common.user.current.forms
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
byceps.blueprints.common.user.settings.forms
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

:Copyright: 2006-2020 Jochen Kupperschmidt
:License: Modified BSD, see LICENSE for details.

R byceps/blueprints/common/user/current/templates/common/user/current/_account.html => byceps/blueprints/common/user/settings/templates/common/user/settings/_account.html +0 -0
R byceps/blueprints/common/user/current/templates/common/user/current/_details_personal.html => byceps/blueprints/common/user/settings/templates/common/user/settings/_details_personal.html +0 -0
R byceps/blueprints/common/user/current/templates/common/user/current/_newsletter.html => byceps/blueprints/common/user/settings/templates/common/user/settings/_newsletter.html +0 -0
R byceps/blueprints/common/user/current/templates/common/user/current/change_screen_name_form.html => byceps/blueprints/common/user/settings/templates/common/user/settings/change_screen_name_form.html +0 -0
R byceps/blueprints/common/user/current/templates/common/user/current/details_update_form.html => byceps/blueprints/common/user/settings/templates/common/user/settings/details_update_form.html +0 -0
R byceps/blueprints/common/user/current/templates/common/user/current/view.html => byceps/blueprints/common/user/settings/templates/common/user/settings/view.html +3 -3
@@ 19,10 19,10 @@
  </div>

  {%- with label_column_width = '8rem', data_column_min_width = '12rem' %}
{%- include 'common/user/current/_account.html' %}
{%- include 'common/user/current/_details_personal.html' %}
{%- include 'common/user/settings/_account.html' %}
{%- include 'common/user/settings/_details_personal.html' %}
    {%- if g.app_mode.is_site() and newsletter_offered %}
{%- include 'common/user/current/_newsletter.html' %}
{%- include 'common/user/settings/_newsletter.html' %}
    {%- endif %}
  {%- endwith %}


A byceps/blueprints/common/user/settings/views.py => byceps/blueprints/common/user/settings/views.py +160 -0
@@ 0,0 1,160 @@
"""
byceps.blueprints.common.user.settings.views
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

:Copyright: 2006-2020 Jochen Kupperschmidt
:License: Modified BSD, see LICENSE for details.
"""

from flask import abort, g, request

from .....config import get_app_mode
from .....services.country import service as country_service
from .....services.newsletter import service as newsletter_service
from .....services.user import command_service as user_command_service
from .....services.user import service as user_service
from .....signals import user as user_signals
from .....util.framework.blueprint import create_blueprint
from .....util.framework.flash import flash_success
from .....util.framework.templating import templated
from .....util.views import redirect_to

from ...authentication.decorators import login_required

from ..creation.views import _find_newsletter_list_for_brand

from .forms import DetailsForm, ChangeScreenNameForm


blueprint = create_blueprint('user_settings', __name__)


@blueprint.route('')
@login_required
@templated
def view():
    """Show the current user's internal profile."""
    current_user = g.current_user

    user = user_service.find_active_db_user(current_user.id)
    if user is None:
        abort(404)

    if get_app_mode().is_site():
        newsletter_list_id = _find_newsletter_list_for_brand()
        newsletter_offered = newsletter_list_id is not None

        subscribed_to_newsletter = newsletter_service.is_subscribed(
            user.id, newsletter_list_id
        )
    else:
        newsletter_list_id = None
        newsletter_offered = False
        subscribed_to_newsletter = None

    return {
        'user': user,
        'newsletter_offered': newsletter_offered,
        'newsletter_list_id': newsletter_list_id,
        'subscribed_to_newsletter': subscribed_to_newsletter,
    }


@blueprint.route('/screen_name')
@templated
def change_screen_name_form(erroneous_form=None):
    """Show a form to change the current user's screen name."""
    _get_current_user_or_404()

    form = erroneous_form if erroneous_form else ChangeScreenNameForm()

    return {
        'form': form,
    }


@blueprint.route('/screen_name', methods=['POST'])
def change_screen_name():
    """Change the current user's screen name."""
    current_user = _get_current_user_or_404()

    form = ChangeScreenNameForm(request.form)
    if not form.validate():
        return change_screen_name_form(form)

    old_screen_name = current_user.screen_name
    new_screen_name = form.screen_name.data.strip()
    initiator_id = current_user.id

    event = user_command_service.change_screen_name(
        current_user.id, new_screen_name, initiator_id
    )

    user_signals.screen_name_changed.send(None, event=event)

    flash_success(f'Dein Benutzername wurde zu "{new_screen_name}" geändert.')

    return redirect_to('.view')


@blueprint.route('/details')
@templated
def details_update_form(erroneous_form=None):
    """Show a form to update the current user's details."""
    current_user = _get_current_user_or_404()
    user = user_service.find_user_with_details(current_user.id)

    form = erroneous_form if erroneous_form else DetailsForm(obj=user.detail)
    country_names = country_service.get_country_names()

    return {
        'form': form,
        'country_names': country_names,
    }


@blueprint.route('/details', methods=['POST'])
def details_update():
    """Update the current user's details."""
    current_user = _get_current_user_or_404()

    form = DetailsForm(request.form)

    if not form.validate():
        return details_update_form(form)

    first_names = form.first_names.data.strip()
    last_name = form.last_name.data.strip()
    date_of_birth = form.date_of_birth.data
    country = form.country.data.strip()
    zip_code = form.zip_code.data.strip()
    city = form.city.data.strip()
    street = form.street.data.strip()
    phone_number = form.phone_number.data.strip()

    event = user_command_service.update_user_details(
        current_user.id,
        first_names,
        last_name,
        date_of_birth,
        country,
        zip_code,
        city,
        street,
        phone_number,
        current_user.id,  # initiator_id
    )

    flash_success('Deine Daten wurden gespeichert.')

    user_signals.details_updated.send(None, event=event)

    return redirect_to('.view')


def _get_current_user_or_404():
    user = g.current_user
    if not user.is_active:
        abort(404)

    return user

A tests/integration/blueprints/common/user/settings/__init__.py => tests/integration/blueprints/common/user/settings/__init__.py +0 -0
R tests/integration/blueprints/common/user/test_current_user_settings.py => tests/integration/blueprints/common/user/settings/test_views.py +0 -0