integrations.web.events.create_bp

ルート設定

 1"""
 2ルート設定
 3"""
 4
 5from integrations.web.events.create_bp.detail import detail_bp
 6from integrations.web.events.create_bp.graph import graph_bp
 7from integrations.web.events.create_bp.index import index_bp
 8from integrations.web.events.create_bp.member import member_bp
 9from integrations.web.events.create_bp.ranking import ranking_bp
10from integrations.web.events.create_bp.report import report_bp
11from integrations.web.events.create_bp.score import score_bp
12from integrations.web.events.create_bp.summary import summary_bp
13from integrations.web.events.create_bp.user_assets import user_assets_bp
14
15__all__ = [
16    "detail_bp",
17    "graph_bp",
18    "index_bp",
19    "member_bp",
20    "ranking_bp",
21    "report_bp",
22    "score_bp",
23    "summary_bp",
24    "user_assets_bp",
25]
def detail_bp( adapter: integrations.web.adapter.ServiceAdapter) -> flask.blueprints.Blueprint:
19def detail_bp(adapter: "ServiceAdapter") -> Blueprint:
20    """個人成績詳細ページ用Blueprint
21
22    Args:
23        adapter (ServiceAdapter): web用アダプタ
24
25    Returns:
26        Blueprint: Blueprint
27    """
28
29    bp = Blueprint("detail", __name__, url_prefix="/detail")
30
31    @bp.route("/", methods=["GET", "POST"])
32    def detail():
33        if not adapter.conf.view_summary:
34            abort(403)
35
36        padding = current_app.config["padding"]
37        players = current_app.config["players"]
38
39        m = adapter.parser()
40        cookie_data = adapter.functions.get_cookie(request)
41        text = " ".join(cookie_data.values())
42        m.data.text = f"{g.cfg.results.commandword[0]} {text}"
43        libs.dispatcher.by_keyword(m)
44
45        message = adapter.functions.header_message(m)
46
47        for data in m.post.message:
48            for k, v in data.items():
49                msg = v.get("data")
50
51                if not k.isnumeric() and k:
52                    message += f"<h2>{k}</h2>\n"
53
54                if isinstance(msg, pd.DataFrame):
55                    show_index = v["options"].show_index
56                    if k == "戦績" and g.params.get("verbose"):
57                        padding = "0.25em 0.75em"
58                        msg = _conv_verbose(msg)
59                    message += adapter.functions.to_styled_html(msg, padding, show_index)
60                    message = message.replace(f">{g.params["player_name"]}<", f"><div class='player_name'>{g.params["player_name"]}</div><")
61
62                if isinstance(msg, str):
63                    message += adapter.functions.to_text_html(msg)
64
65        cookie_data.update(body=message, players=players, **asdict(adapter.conf))
66        page = adapter.functions.set_cookie("detail.html", request, cookie_data)
67
68        return page
69
70    return bp

個人成績詳細ページ用Blueprint

Arguments:
  • adapter (ServiceAdapter): web用アダプタ
Returns:

Blueprint: Blueprint

def graph_bp( adapter: integrations.web.adapter.ServiceAdapter) -> flask.blueprints.Blueprint:
20def graph_bp(adapter: "ServiceAdapter") -> Blueprint:
21    """グラフ表示ページ用Blueprint
22
23    Args:
24        adapter (ServiceAdapter): web用アダプタ
25
26    Returns:
27        Blueprint: Blueprint
28    """
29
30    bp = Blueprint("graph", __name__, url_prefix="/graph")
31
32    @bp.route("/", methods=["GET", "POST"])
33    def graph():
34        if not adapter.conf.view_graph:
35            abort(403)
36
37        padding = current_app.config["padding"]
38
39        m = adapter.parser()
40        cookie_data = adapter.functions.get_cookie(request)
41        text = " ".join(cookie_data.values())
42        m.data.text = f"{g.cfg.graph.commandword[0]} {text}"
43        libs.dispatcher.by_keyword(m)
44
45        message = adapter.functions.header_message(m)
46
47        for data in m.post.message:
48            for k, v in data.items():
49                msg = v.get("data")
50
51                if isinstance(msg, PosixPath) and msg.exists():
52                    message += f"<p>\n{msg.read_text(encoding="utf-8")}\n</p>\n"
53
54                if isinstance(msg, pd.DataFrame) and k == "素点情報":
55                    show_index = v["options"].show_index
56                    msg["ゲーム数"] = msg["ゲーム数"].astype("float")
57                    msg.rename(columns={"平均値(x)": "平均値", "中央値(|)": "中央値"}, inplace=True)
58                    message += f"<h2>{k}</h2>\n"
59                    message += adapter.functions.to_styled_html(msg, padding, show_index)
60
61                if isinstance(msg, pd.DataFrame) and k == "順位/ポイント情報":
62                    show_index = v["options"].show_index
63                    msg["ゲーム数"] = msg["ゲーム数"].astype("float")
64                    multi = [
65                        ("", "ゲーム数"),
66                        ("1位", "獲得数"),
67                        ("1位", "獲得率"),
68                        ("2位", "獲得数"),
69                        ("2位", "獲得率"),
70                        ("3位", "獲得数"),
71                        ("3位", "獲得率"),
72                        ("4位", "獲得数"),
73                        ("4位", "獲得率"),
74                        ("", "平均順位"),
75                        ("区間成績", "区間ポイント"),
76                        ("区間成績", "区間平均"),
77                        ("", "通算ポイント"),
78                    ]
79                    msg.columns = pd.MultiIndex.from_tuples(multi)
80                    message += f"<h2>{k}</h2>\n"
81                    message += adapter.functions.to_styled_html(msg, padding, show_index)
82
83        cookie_data.update(body=message, **asdict(adapter.conf))
84        page = adapter.functions.set_cookie("graph.html", request, cookie_data)
85
86        return page
87
88    return bp

グラフ表示ページ用Blueprint

Arguments:
  • adapter (ServiceAdapter): web用アダプタ
Returns:

Blueprint: Blueprint

def index_bp( adapter: integrations.web.adapter.ServiceAdapter) -> flask.blueprints.Blueprint:
15def index_bp(adapter: "ServiceAdapter") -> Blueprint :
16    """index用Blueprint
17
18    Args:
19        adapter (ServiceAdapter): web用アダプタ
20
21    Returns:
22        Blueprint: Blueprint
23    """
24
25    bp = Blueprint("index", __name__, url_prefix="/")
26
27    @bp.route("/", methods=["GET", "POST"])
28    def index():
29        return render_template("index.html", **asdict(adapter.conf))
30
31    return bp

index用Blueprint

Arguments:
  • adapter (ServiceAdapter): web用アダプタ
Returns:

Blueprint: Blueprint

def member_bp( adapter: integrations.web.adapter.ServiceAdapter) -> flask.blueprints.Blueprint:
18def member_bp(adapter: "ServiceAdapter") -> Blueprint:
19    """メンバー管理ページ用Blueprint
20
21    Args:
22        adapter (ServiceAdapter): web用アダプタ
23
24    Returns:
25        Blueprint: Blueprint
26    """
27
28    bp = Blueprint("member", __name__, url_prefix="/member")
29
30    @bp.route("/", methods=["GET", "POST"])
31    def mgt_member():
32        if not adapter.conf.management_member:
33            abort(403)
34
35        padding = current_app.config["padding"]
36        data: dict = asdict(adapter.conf)
37
38        if request.method == "POST":
39            match request.form.get("action"):
40                case "add_member":
41                    if (name := request.form.get("member", "").strip()):
42                        ret = member.append(name.split()[0:2])
43                        data.update(result_msg=ret)
44                case "del_member":
45                    if (name := request.form.get("member", "").strip()):
46                        ret = member.remove(name.split()[0:2])
47                        data.update(result_msg=ret)
48                case "add_team":
49                    if (team_name := request.form.get("team", "").strip()):
50                        ret = team.append(team_name.split()[0:2])
51                        data.update(result_msg=ret)
52                case "del_team":
53                    if (team_name := request.form.get("team", "").strip()):
54                        ret = team.remove(team_name.split()[0:2])
55                        data.update(result_msg=ret)
56                case "delete_all_team":
57                    ret = team.clear()
58                    data.update(result_msg=ret)
59
60        member_df = loader.read_data("MEMBER_INFO")
61        if member_df.empty:
62            data.update(member_table="<p>登録済みメンバーはいません。</p>")
63        else:
64            data.update(member_table=adapter.functions.to_styled_html(member_df, padding))
65
66        team_df = loader.read_data("TEAM_INFO")
67        if team_df.empty:
68            data.update(team_table="<p>登録済みチームはありません。</p>")
69        else:
70            data.update(team_table=adapter.functions.to_styled_html(team_df, padding))
71
72        return render_template("registry.html", **data)
73
74    return bp

メンバー管理ページ用Blueprint

Arguments:
  • adapter (ServiceAdapter): web用アダプタ
Returns:

Blueprint: Blueprint

def ranking_bp( adapter: integrations.web.adapter.ServiceAdapter) -> flask.blueprints.Blueprint:
19def ranking_bp(adapter: "ServiceAdapter") -> Blueprint:
20    """ランキングページ用Blueprint
21
22    Args:
23        adapter (ServiceAdapter): web用アダプタ
24
25    Returns:
26        Blueprint: Blueprint
27    """
28
29    bp = Blueprint("ranking", __name__, url_prefix="/ranking")
30
31    @bp.route("/", methods=["GET", "POST"])
32    def ranking():
33        if not adapter.conf.view_ranking:
34            abort(403)
35
36        padding = current_app.config["padding"]
37
38        m = adapter.parser()
39        cookie_data = adapter.functions.get_cookie(request)
40        text = " ".join(cookie_data.values())
41        m.data.text = f"{g.cfg.ranking.commandword[0]} {text}"
42        libs.dispatcher.by_keyword(m)
43
44        message = adapter.functions.header_message(m)
45
46        for data in m.post.message:
47            for k, v in data.items():
48                msg = v.get("data")
49
50                if not k.isnumeric() and k:
51                    message += f"<h2>{k}</h2>\n"
52
53                if isinstance(msg, pd.DataFrame):
54                    show_index = v["options"].show_index
55                    message += adapter.functions.to_styled_html(msg, padding, show_index)
56
57                if isinstance(msg, str):
58                    message += adapter.functions.to_text_html(msg)
59
60        cookie_data.update(body=message, **asdict(adapter.conf))
61        page = adapter.functions.set_cookie("ranking.html", request, cookie_data)
62
63        return page
64
65    return bp

ランキングページ用Blueprint

Arguments:
  • adapter (ServiceAdapter): web用アダプタ
Returns:

Blueprint: Blueprint

def report_bp( adapter: integrations.web.adapter.ServiceAdapter) -> flask.blueprints.Blueprint:
19def report_bp(adapter: "ServiceAdapter") -> Blueprint:
20    """レポートページ用Blueprint
21
22    Args:
23        adapter (ServiceAdapter): web用アダプタ
24
25    Returns:
26        Blueprint: Blueprint
27    """
28
29    bp = Blueprint("report", __name__, url_prefix="/report")
30
31    @bp.route("/", methods=["GET", "POST"])
32    def report():
33        if not adapter.conf.view_report:
34            abort(403)
35
36        padding = current_app.config["padding"]
37
38        m = adapter.parser()
39        cookie_data = adapter.functions.get_cookie(request)
40        text = " ".join(cookie_data.values())
41        m.data.text = f"{g.cfg.report.commandword[0]} {text}"
42        libs.dispatcher.by_keyword(m)
43
44        message = adapter.functions.header_message(m)
45
46        for data in m.post.message:
47            for k, v in data.items():
48                msg = v.get("data")
49
50                if not k.isnumeric() and k:
51                    message += f"<h2>{k}</h2>\n"
52
53                if isinstance(msg, pd.DataFrame):
54                    show_index = v["options"].show_index
55                    if {"個人成績一覧", "チーム成績一覧"} & set(m.post.headline):
56                        check_column = msg.columns.to_list()
57                        multi = [
58                            ("", "名前" if g.params.get("individual", True) else "チーム"),
59                            ("", "ゲーム数"),
60                            ("ポイント", "通算") if {"通算", "平均"}.issubset(check_column) else None,
61                            ("ポイント", "平均") if {"通算", "平均"}.issubset(check_column) else None,
62                            ("1位", "獲得数") if {"1位数", "1位率"}.issubset(check_column) else None,
63                            ("1位", "獲得率") if {"1位数", "1位率"}.issubset(check_column) else None,
64                            ("2位", "獲得数") if {"2位数", "2位率"}.issubset(check_column) else None,
65                            ("2位", "獲得率") if {"2位数", "2位率"}.issubset(check_column) else None,
66                            ("3位", "獲得数") if {"3位数", "3位率"}.issubset(check_column) else None,
67                            ("3位", "獲得率") if {"3位数", "3位率"}.issubset(check_column) else None,
68                            ("4位", "獲得数") if {"4位数", "4位率"}.issubset(check_column) else None,
69                            ("4位", "獲得率") if {"4位数", "4位率"}.issubset(check_column) else None,
70                            ("平均順位", "") if {"平均順位", "平順"} & set(check_column) else None,
71                            ("トビ", "回数") if {"トビ数", "トビ率"}.issubset(check_column) else None,
72                            ("トビ", "率") if {"トビ数", "トビ率"}.issubset(check_column) else None,
73                            ("役満", "和了数") if {"役満和了数", "役満和了率"}.issubset(check_column) else None,
74                            ("役満", "和了率") if {"役満和了数", "役満和了率"}.issubset(check_column) else None,
75                        ]
76                        msg.columns = pd.MultiIndex.from_tuples([x for x in multi if x is not None])
77                    elif "成績上位者" in m.post.headline.keys():
78                        name = "名前" if g.params.get("individual", True) else "チーム"
79                        check_column = msg.columns.to_list()
80                        multi = [
81                            ("", "集計月"),
82                            ("1位", name), ("1位", "獲得ポイント"),
83                            ("2位", name), ("2位", "獲得ポイント"),
84                            ("3位", name), ("3位", "獲得ポイント"),
85                            ("4位", name), ("4位", "獲得ポイント"),
86                            ("5位", name), ("5位", "獲得ポイント"),
87                        ]
88                        msg.columns = pd.MultiIndex.from_tuples([x for x in multi if x is not None])
89                    message += adapter.functions.to_styled_html(msg, padding, show_index)
90
91                if isinstance(msg, str):
92                    message += adapter.functions.to_text_html(msg)
93
94        cookie_data.update(body=message, **asdict(adapter.conf))
95        page = adapter.functions.set_cookie("report.html", request, cookie_data)
96
97        return page
98
99    return bp

レポートページ用Blueprint

Arguments:
  • adapter (ServiceAdapter): web用アダプタ
Returns:

Blueprint: Blueprint

def score_bp( adapter: integrations.web.adapter.ServiceAdapter) -> flask.blueprints.Blueprint:
 22def score_bp(adapter: "ServiceAdapter") -> Blueprint:
 23    """スコア管理ページ用Blueprint
 24
 25    Args:
 26        adapter (ServiceAdapter): web用アダプタ
 27
 28    Returns:
 29        Blueprint: Blueprint
 30    """
 31
 32    bp = Blueprint("score", __name__, url_prefix="/score")
 33
 34    @bp.route("/", methods=["GET", "POST"])
 35    def mgt_score():
 36        if not adapter.conf.management_score:
 37            abort(403)
 38
 39        padding = current_app.config["padding"]
 40        players = current_app.config["players"]
 41        m = adapter.parser()
 42
 43        def score_table() -> str:
 44            df = formatter.df_rename(pd.read_sql(
 45                sql="""
 46                select
 47                    '<input type="radio" name="ts" value="' || ts || '">' as '#',
 48                    playtime,
 49                    p1_name, p1_str,
 50                    p2_name, p2_str,
 51                    p3_name, p3_str,
 52                    p4_name, p4_str,
 53                    comment
 54                from
 55                    result
 56                order by
 57                    ts desc
 58                limit 0, 10
 59                ;
 60                """,
 61                con=dbutil.connection(g.cfg.setting.database_file)
 62            ))
 63
 64            if not isinstance(df.columns, pd.MultiIndex):
 65                new_columns = [tuple(col.split(" ")) if " " in col else ("", col) for col in df.columns]
 66                df.columns = pd.MultiIndex.from_tuples(new_columns, names=["座席", "項目"])
 67
 68            return adapter.functions.to_styled_html(df, padding)
 69
 70        data: dict = asdict(adapter.conf)
 71        data.update(players=players)
 72
 73        if request.method == "POST":
 74            data.update(request.form.to_dict())
 75            data.update(mode="update")
 76            data.update(g.cfg.mahjong.to_dict())
 77
 78            if "ts" in data:
 79                match request.form.get("action"):
 80                    case "modify":
 81                        sql = "select * from result where ts = :ts;"
 82                        df = pd.read_sql(sql=sql, con=dbutil.connection(g.cfg.setting.database_file), params=data)
 83                        data.update(next(iter(df.T.to_dict().values())))
 84                        return render_template("score_input.html", **data)
 85                    case "delete":
 86                        m.data.event_ts = request.form.get("ts", "")
 87                        modify.db_delete(m)
 88                        data.update(table=score_table())
 89                        return render_template("score_list.html", **data)
 90                    case "update":
 91                        g.params.update(unregistered_replace=False)
 92                        data.update(request.form.to_dict(), players=players)
 93                        if (p1_name := request.form.get("p1_other")):
 94                            data.update(p1_name=formatter.name_replace(p1_name))
 95                        if (p2_name := request.form.get("p2_other")):
 96                            data.update(p2_name=formatter.name_replace(p2_name))
 97                        if (p3_name := request.form.get("p3_other")):
 98                            data.update(p3_name=formatter.name_replace(p3_name))
 99                        if (p4_name := request.form.get("p4_other")):
100                            data.update(p4_name=formatter.name_replace(p4_name))
101                        if not request.form.get("comment"):
102                            data.update(comment=None)
103
104                        detection = GameResult(**data)
105                        m.status.source = "web"
106                        if data.get("mode") == "insert":
107                            modify.db_insert(detection, m)
108                        else:
109                            modify.db_update(detection, m)
110
111                        data.update(table=score_table())
112                        return render_template("score_list.html", **data)
113            elif request.form.get("action") == "modify":  # 新規登録
114                playtime = ExtDT()
115                data.update(mode="insert", playtime=playtime.format(fmt="sql"), ts=playtime.format(fmt="ts"))
116                return render_template("score_input.html", **data)
117
118        data.update(table=score_table())
119        return render_template("score_list.html", **data)
120
121    return bp

スコア管理ページ用Blueprint

Arguments:
  • adapter (ServiceAdapter): web用アダプタ
Returns:

Blueprint: Blueprint

def summary_bp( adapter: integrations.web.adapter.ServiceAdapter) -> flask.blueprints.Blueprint:
19def summary_bp(adapter: "ServiceAdapter") -> Blueprint:
20    """成績サマリページ用Blueprint
21
22    Args:
23        adapter (ServiceAdapter): web用アダプタ
24
25    Returns:
26        Blueprint: Blueprint
27    """
28
29    bp = Blueprint("summary", __name__, url_prefix="/summary")
30
31    @bp.route("/", methods=["GET", "POST"])
32    def summary():
33        if not adapter.conf.view_summary:
34            abort(403)
35
36        padding = current_app.config["padding"]
37
38        m = adapter.parser()
39        cookie_data = adapter.functions.get_cookie(request)
40        text = " ".join(cookie_data.values())
41        m.data.text = f"{g.cfg.results.commandword[0]} {text}"
42        libs.dispatcher.by_keyword(m)
43
44        message = adapter.functions.header_message(m)
45
46        for data in m.post.message:
47            for k, v in data.items():
48                msg = v.get("data")
49
50                if not k.isnumeric() and k:
51                    message += f"<h2>{k}</h2>\n"
52
53                if isinstance(msg, pd.DataFrame):
54                    show_index = v["options"].show_index
55                    if k == "戦績" and g.params.get("verbose"):
56                        padding = "0.25em 0.75em"
57                        msg = _conv_verbose(msg)
58
59                    message += adapter.functions.to_styled_html(msg, padding, show_index)
60
61                if isinstance(msg, str):
62                    message += adapter.functions.to_text_html(msg)
63
64        cookie_data.update(body=message, **asdict(adapter.conf))
65        page = adapter.functions.set_cookie("summary.html", request, cookie_data)
66
67        return page
68
69    return bp

成績サマリページ用Blueprint

Arguments:
  • adapter (ServiceAdapter): web用アダプタ
Returns:

Blueprint: Blueprint

def user_assets_bp( adapter: integrations.web.adapter.ServiceAdapter) -> flask.blueprints.Blueprint:
17def user_assets_bp(adapter: "ServiceAdapter") -> Blueprint:
18    """ユーザー指定CSS用Blueprint
19
20    Args:
21        adapter (ServiceAdapter): web用アダプタ
22
23    Returns:
24        Blueprint: Blueprint
25    """
26
27    bp = Blueprint(
28        "user_assets",
29        __name__,
30        static_folder=os.path.dirname(os.path.join(g.cfg.config_dir, adapter.conf.custom_css)),
31        static_url_path="/user_static"
32    )
33
34    @bp.before_request
35    def restrict_static():
36        if not os.path.basename(request.path) == adapter.conf.custom_css:
37            abort(403)
38
39    return bp

ユーザー指定CSS用Blueprint

Arguments:
  • adapter (ServiceAdapter): web用アダプタ
Returns:

Blueprint: Blueprint