marcus67/little_brother

View on GitHub
little_brother/web/admin_view_handler.py

Summary

Maintainability
A
1 hr
Test Coverage
# -*- coding: utf-8 -*-

# Copyright (C) 2019-21  Marcus Rickert
#
# See https://github.com/marcus67/little_brother
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

import re

import flask
import flask_login

from little_brother import constants, entity_forms
from little_brother import rule_override
from little_brother.persistence.session_context import SessionContext
from little_brother.web.base_view_handler import BaseViewHandler
from python_base_app import tools
from some_flask_helpers import blueprint_adapter

TIME_EXTENSION_SUBMIT_PATTERN = "time_extension_{username}_(off|-?[0-9]+)"

BLUEPRINT_ADAPTER = blueprint_adapter.BlueprintAdapter()


# Dummy function to trigger extraction by pybabel...
def _(x):
    return x


class AdminViewHandler(BaseViewHandler):

    def __init__(self, p_package):

        super().__init__(p_blueprint_name=constants.ADMIN_BLUEPRINT_NAME, p_blueprint_adapter=BLUEPRINT_ADAPTER,
                         p_package=p_package)

    @BLUEPRINT_ADAPTER.route_method("/admin", endpoint="main_view", methods=["GET", "POST"])
    @flask_login.login_required
    def admin_view(self):

        request = flask.request
        with tools.TimingContext(lambda duration: self.measure(p_hostname=request.remote_addr,
                                                               p_service=self.simplify_url(request.url_rule),
                                                               p_duration=duration)):
            with SessionContext(p_persistence=self.persistence) as session_context:

                try:
                    admin_infos = self.admin_data_handler.get_admin_infos(
                        p_session_context=session_context,
                        p_process_infos=self.processs_handler_manager.get_process_infos(),
                        p_user_names=self.user_manager.usernames)

                    forms = self.get_admin_forms(p_admin_infos=admin_infos)

                    valid_and_submitted, submitted = self.validate(p_forms=forms)

                    if valid_and_submitted:
                        self.save_admin_data(admin_infos, forms)
                        self.handle_button_press(admin_infos, request, session_context)
                        return flask.redirect(flask.url_for("admin.main_view"))

                    if not submitted:
                        self.load_from_model(admin_infos, forms)

                    template_dict = {}
                    self.add_general_template_data(p_dict=template_dict)
                    template_dict["forms"] = forms
                    template_dict["admin_infos"] = admin_infos
                    template_dict["navigation"] = {
                        'current_view': constants.ADMIN_BLUEPRINT_NAME + "." + constants.ADMIN_VIEW_NAME
                    }
                    self.add_version_info(p_dict=template_dict)

                    page = flask.render_template(constants.ADMIN_HTML_TEMPLATE, **template_dict)

                except Exception as e:
                    return self.handle_rendering_exception(p_page_name="admin page", p_exception=e)

                return page

    def load_from_model(self, p_admin_infos, p_forms):

        for admin_info in p_admin_infos:
            for day_info in admin_info.day_infos:
                p_forms[day_info.html_key].load_from_model(p_model=day_info.override)

    def handle_button_press(self, p_admin_infos, p_request, p_session_context):

        for admin_info in p_admin_infos:
            username = admin_info.username
            submit_regex = re.compile(TIME_EXTENSION_SUBMIT_PATTERN.format(username=username))
            result = submit_regex.match(p_request.form['submit'])

            if result is not None:
                delta = int(result.group(1))

                self.time_extension_entity_manager.set_time_extension_for_admin_info_and_session(
                    p_session_context=p_session_context, p_user_name=username,
                    p_admin_info=admin_info, p_delta=delta)

    @staticmethod
    def get_admin_forms(p_admin_infos):

        forms = {}

        forms['dummy'] = entity_forms.DummyAdminForm(meta={'csrf': True})

        for admin_info in p_admin_infos:
            for day_info in admin_info.day_infos:
                form = rule_override.RuleOverrideForm(prefix=day_info.html_key + '_', meta={'csrf': True})
                forms[day_info.html_key] = form

        return forms

    def save_admin_data(self, p_admin_infos, p_forms):

        for admin_info in p_admin_infos:
            for day_info in admin_info.day_infos:
                form = p_forms[day_info.html_key]

                if form.differs_from_model(p_model=day_info.override):
                    form.save_to_model(p_model=day_info.override)
                    self.admin_data_handler.update_rule_override(day_info.override)