libs.commands.registry.member

libs/commands/registry/member.py

  1"""
  2libs/commands/registry/member.py
  3"""
  4
  5import logging
  6from typing import TYPE_CHECKING, TypedDict, cast
  7
  8import libs.global_value as g
  9from libs.bootstrap.section import BaseSection
 10from libs.domain import modify
 11from libs.types import CommandType
 12from libs.utils import dbutil, textutil, validator
 13
 14if TYPE_CHECKING:
 15    from configparser import ConfigParser, SectionProxy
 16
 17    from libs.bootstrap.app_config import AppConfig
 18
 19
 20class MemberDataDict(TypedDict):
 21    """メンバー情報格納辞書"""
 22
 23    id: int
 24    """メンバーID"""
 25    name: str
 26    """メンバー名"""
 27    alias: list[str]
 28    """別名リスト"""
 29    team: str
 30    """所属チーム"""
 31    last_update: int
 32    """最終更新日"""
 33    elapsed_day: int
 34    """経過日数"""
 35    game_count: int
 36    """プレイゲーム数"""
 37
 38
 39class MemberSection(BaseSection):
 40    """memberセクション処理"""
 41
 42    default_commandword: str
 43    """コマンドワードデフォルト値"""
 44    commandword: list[str]
 45    """呼び出しキーワード"""
 46    command_suffix: list[str]
 47    """コマンド接尾辞(登録キーワード+接尾辞を呼び出しキーワードとして扱う)"""
 48
 49    section: str
 50    main_parser: "ConfigParser"
 51
 52    info: list[MemberDataDict]
 53    """メンバー情報(キャッシュデータ)"""
 54    registration_limit: int
 55    """登録メンバー上限数"""
 56    character_limit: int
 57    """名前に使用できる文字数"""
 58    alias_limit: int
 59    """別名登録上限数"""
 60    guest_name: str
 61    """未登録メンバー名称"""
 62
 63    def __init__(self, outer: "AppConfig") -> None:
 64        self.default_commandword = "メンバー一覧"
 65        self.section = str(CommandType.MEMBER_LIST)
 66        self.main_parser = outer.main_parser
 67        self._reset()
 68
 69    def _reset(self) -> None:
 70        self.info = []
 71        self.commandword = []
 72        self.command_suffix = []
 73        self.registration_limit = int(255)
 74        self.character_limit = int(8)
 75        self.alias_limit = int(16)
 76        self.guest_name = str("ゲスト")
 77
 78    def config_load(self, section_proxy: "SectionProxy") -> None:
 79        """
 80        設定値取り込み
 81
 82        Args:
 83            section_proxy (SectionProxy): 読み込み先(パーサー + セクション名)
 84
 85        """
 86        self._reset()
 87        self.initialization(section_proxy)
 88
 89        # 呼び出しキーワード取り込み
 90        self.commandword = self.getlist("commandword", fallback=self.default_commandword)
 91
 92        logging.trace("%s: %s", self.section, self)  # type: ignore
 93
 94    def resolve_name(self, name: str) -> str:
 95        """
 96        別名からメンバー名を逆引き
 97
 98        Args:
 99            name (str): 変換する名前
100
101        Returns:
102            str: メンバー名(見つからない場合は空欄)
103
104        """
105        for x in self.info:
106            if name in x["alias"]:
107                return x["name"]
108
109        return ""
110
111    def alias(self, name: str) -> list[str]:
112        """
113        指定メンバーの別名をリストで返す
114
115        Args:
116            name (str): メンバー名
117
118        Returns:
119            list[str]: 別名リスト
120
121        """
122        for x in self.info:
123            if x.get("name") == name:
124                return x.get("alias")
125        return []
126
127    @property
128    def lists(self) -> list[str]:
129        """メンバー名一覧をリストで返す"""
130        return [x.get("name") for x in self.info]
131
132    @property
133    def all_lists(self) -> list[str]:
134        """
135        メンバー名、別名をすべてリストで返す
136
137        Returns:
138            list[str]: メンバー名、別名のリスト
139
140        """
141        ret: list[str] = []
142        for name in self.lists:
143            ret.append(name)
144            ret.extend(self.alias(name))
145
146        return list(set(ret))
147
148    @property
149    def get_info(self) -> list[MemberDataDict]:
150        """
151        全メンバー情報取得
152
153        Returns:
154            list[MemberDataDict]: メンバー情報
155
156        """
157        ret = g.params.read_data("MEMBER_INFO").to_dict(orient="records")
158        for row in ret:
159            row.update(alias=str(row["alias"]).split(","))
160
161        return cast(list[MemberDataDict], ret)
162
163
164def append(argument: list[str]) -> str:
165    """
166    メンバー追加
167
168    Args:
169        argument (list[str]): 登録情報
170            - argument[0]: 登録するメンバー名
171            - argument[1]: 登録する別名
172
173    Returns:
174        str: 処理結果
175
176    """
177    resultdb = dbutil.connection(g.cfg.setting.database_file)
178
179    ret: bool = False
180    dbupdate_flg: bool = False
181    msg: str = "使い方が間違っています。"
182
183    if len(argument) == 1:  # 新規追加
184        new_name = textutil.str_conv(argument[0], textutil.ConversionType.HtoZ)
185        rows = resultdb.execute("select count() from member")
186        count = rows.fetchone()[0]
187        if count > g.cfg.member.registration_limit:
188            msg = "登録上限を超えています。"
189        else:  # 登録処理
190            ret, msg = validator.check_namepattern(new_name, "member")
191            if ret:
192                resultdb.execute(
193                    "insert into member(name) values (?)",
194                    (new_name,),
195                )
196                resultdb.execute(
197                    "insert into alias(name, member) values (?,?)",
198                    (new_name, new_name),
199                )
200                msg = f"「{new_name}」を登録しました。"
201                logging.info("add new member: %s", new_name)
202
203    if len(argument) == 2:  # 別名登録
204        new_name = textutil.str_conv(argument[0], textutil.ConversionType.HtoZ)
205        nic_name = textutil.str_conv(argument[1], textutil.ConversionType.HtoZ)
206        registration_flg = True
207        rows = resultdb.execute(
208            "select count() from alias where member=?",
209            (new_name,),
210        )
211        count = rows.fetchone()[0]
212        if count == 0:
213            msg = f"「{new_name}」はまだ登録されていません。"
214            registration_flg = False
215        if count > g.cfg.member.alias_limit:
216            msg = "登録上限を超えています。"
217            registration_flg = False
218
219        if registration_flg:  # 登録処理
220            ret, msg = validator.check_namepattern(nic_name, "member")
221            if ret:
222                resultdb.execute(
223                    "insert into alias(name, member) values (?,?)",
224                    (nic_name, new_name),
225                )
226                msg = f"「{new_name}」に「{nic_name}」を追加しました。"
227                logging.info("add alias: %s -> %s", new_name, nic_name)
228                dbupdate_flg = True
229
230        if dbupdate_flg:
231            rows = resultdb.execute(
232                """
233                select distinct name from (
234                    select p1_name as name from result
235                    union all select p2_name from result
236                    union all select p3_name from result
237                    union all select p4_name from result
238                    union all select name from remarks
239                );
240                """
241            )
242            name_list = [row["name"] for row in rows.fetchall()]
243
244            if {
245                nic_name,
246                textutil.str_conv(nic_name, textutil.ConversionType.KtoH),
247                textutil.str_conv(nic_name, textutil.ConversionType.HtoK),
248            } & set(name_list):
249                msg += modify.db_backup()
250                for tbl, col in [("result", f"p{x}_name") for x in range(1, 5)] + [("remarks", "name")]:
251                    resultdb.execute(
252                        f"update {tbl} set {col}=? where {col}=?",
253                        (new_name, nic_name),
254                    )
255                    resultdb.execute(
256                        f"update {tbl} set {col}=? where {col}=?",
257                        (new_name, textutil.str_conv(nic_name, textutil.ConversionType.KtoH)),
258                    )
259                    resultdb.execute(
260                        f"update {tbl} set {col}=? where {col}=?",
261                        (new_name, textutil.str_conv(nic_name, textutil.ConversionType.HtoK)),
262                    )
263                msg += "\nデータベースを更新しました。"
264
265    resultdb.commit()
266    resultdb.close()
267
268    g.cfg.member.info = g.cfg.member.get_info
269
270    return msg
271
272
273def remove(argument: list[str]) -> str:
274    """
275    メンバー削除
276
277    Args:
278        argument (list[str]): 削除情報
279            - argument[0]: 削除するメンバー名
280            - argument[1]: 削除する別名
281
282    Returns:
283        str: 処理結果
284
285    """
286    resultdb = dbutil.connection(g.cfg.setting.database_file)
287    msg = "使い方が間違っています。"
288
289    if len(argument) == 1:  # メンバー削除
290        new_name = textutil.str_conv(argument[0], textutil.ConversionType.HtoZ)
291        if new_name in g.cfg.member.lists:
292            resultdb.execute(
293                "delete from member where name=?",
294                (new_name,),
295            )
296            resultdb.execute(
297                "delete from alias where member=?",
298                (new_name,),
299            )
300            msg = f"「{new_name}」を削除しました。"
301            logging.info("remove member: %s", new_name)
302        else:
303            msg = f"「{new_name}」は登録されていません。"
304
305    if len(argument) == 2:  # 別名削除
306        new_name = textutil.str_conv(argument[0], textutil.ConversionType.HtoZ)
307        nic_name = textutil.str_conv(argument[1], textutil.ConversionType.HtoZ)
308        if nic_name in g.cfg.member.lists:
309            resultdb.execute(
310                "delete from alias where name=? and member=?",
311                (nic_name, new_name),
312            )
313            msg = f"「{new_name}」から「{nic_name}」を削除しました。"
314            logging.info("alias remove: %s -> %s", new_name, nic_name)
315        else:
316            msg = f"「{new_name}」に「{nic_name}」は登録されていません。"
317
318    resultdb.commit()
319    resultdb.close()
320
321    g.cfg.member.info = g.cfg.member.get_info
322
323    return msg
class MemberDataDict(typing.TypedDict):
21class MemberDataDict(TypedDict):
22    """メンバー情報格納辞書"""
23
24    id: int
25    """メンバーID"""
26    name: str
27    """メンバー名"""
28    alias: list[str]
29    """別名リスト"""
30    team: str
31    """所属チーム"""
32    last_update: int
33    """最終更新日"""
34    elapsed_day: int
35    """経過日数"""
36    game_count: int
37    """プレイゲーム数"""

メンバー情報格納辞書

id: int

メンバーID

name: str

メンバー名

alias: list[str]

別名リスト

team: str

所属チーム

last_update: int

最終更新日

elapsed_day: int

経過日数

game_count: int

プレイゲーム数

class MemberSection(libs.bootstrap.section.BaseSection):
 40class MemberSection(BaseSection):
 41    """memberセクション処理"""
 42
 43    default_commandword: str
 44    """コマンドワードデフォルト値"""
 45    commandword: list[str]
 46    """呼び出しキーワード"""
 47    command_suffix: list[str]
 48    """コマンド接尾辞(登録キーワード+接尾辞を呼び出しキーワードとして扱う)"""
 49
 50    section: str
 51    main_parser: "ConfigParser"
 52
 53    info: list[MemberDataDict]
 54    """メンバー情報(キャッシュデータ)"""
 55    registration_limit: int
 56    """登録メンバー上限数"""
 57    character_limit: int
 58    """名前に使用できる文字数"""
 59    alias_limit: int
 60    """別名登録上限数"""
 61    guest_name: str
 62    """未登録メンバー名称"""
 63
 64    def __init__(self, outer: "AppConfig") -> None:
 65        self.default_commandword = "メンバー一覧"
 66        self.section = str(CommandType.MEMBER_LIST)
 67        self.main_parser = outer.main_parser
 68        self._reset()
 69
 70    def _reset(self) -> None:
 71        self.info = []
 72        self.commandword = []
 73        self.command_suffix = []
 74        self.registration_limit = int(255)
 75        self.character_limit = int(8)
 76        self.alias_limit = int(16)
 77        self.guest_name = str("ゲスト")
 78
 79    def config_load(self, section_proxy: "SectionProxy") -> None:
 80        """
 81        設定値取り込み
 82
 83        Args:
 84            section_proxy (SectionProxy): 読み込み先(パーサー + セクション名)
 85
 86        """
 87        self._reset()
 88        self.initialization(section_proxy)
 89
 90        # 呼び出しキーワード取り込み
 91        self.commandword = self.getlist("commandword", fallback=self.default_commandword)
 92
 93        logging.trace("%s: %s", self.section, self)  # type: ignore
 94
 95    def resolve_name(self, name: str) -> str:
 96        """
 97        別名からメンバー名を逆引き
 98
 99        Args:
100            name (str): 変換する名前
101
102        Returns:
103            str: メンバー名(見つからない場合は空欄)
104
105        """
106        for x in self.info:
107            if name in x["alias"]:
108                return x["name"]
109
110        return ""
111
112    def alias(self, name: str) -> list[str]:
113        """
114        指定メンバーの別名をリストで返す
115
116        Args:
117            name (str): メンバー名
118
119        Returns:
120            list[str]: 別名リスト
121
122        """
123        for x in self.info:
124            if x.get("name") == name:
125                return x.get("alias")
126        return []
127
128    @property
129    def lists(self) -> list[str]:
130        """メンバー名一覧をリストで返す"""
131        return [x.get("name") for x in self.info]
132
133    @property
134    def all_lists(self) -> list[str]:
135        """
136        メンバー名、別名をすべてリストで返す
137
138        Returns:
139            list[str]: メンバー名、別名のリスト
140
141        """
142        ret: list[str] = []
143        for name in self.lists:
144            ret.append(name)
145            ret.extend(self.alias(name))
146
147        return list(set(ret))
148
149    @property
150    def get_info(self) -> list[MemberDataDict]:
151        """
152        全メンバー情報取得
153
154        Returns:
155            list[MemberDataDict]: メンバー情報
156
157        """
158        ret = g.params.read_data("MEMBER_INFO").to_dict(orient="records")
159        for row in ret:
160            row.update(alias=str(row["alias"]).split(","))
161
162        return cast(list[MemberDataDict], ret)

memberセクション処理

MemberSection(outer: libs.bootstrap.app_config.AppConfig)
64    def __init__(self, outer: "AppConfig") -> None:
65        self.default_commandword = "メンバー一覧"
66        self.section = str(CommandType.MEMBER_LIST)
67        self.main_parser = outer.main_parser
68        self._reset()
default_commandword: str

コマンドワードデフォルト値

commandword: list[str]

呼び出しキーワード

command_suffix: list[str]

コマンド接尾辞(登録キーワード+接尾辞を呼び出しキーワードとして扱う)

section: str

セクション名

main_parser: configparser.ConfigParser

設定パーサー

info: list[MemberDataDict]

メンバー情報(キャッシュデータ)

registration_limit: int

登録メンバー上限数

character_limit: int

名前に使用できる文字数

alias_limit: int

別名登録上限数

guest_name: str

未登録メンバー名称

def config_load(self, section_proxy: configparser.SectionProxy) -> None:
79    def config_load(self, section_proxy: "SectionProxy") -> None:
80        """
81        設定値取り込み
82
83        Args:
84            section_proxy (SectionProxy): 読み込み先(パーサー + セクション名)
85
86        """
87        self._reset()
88        self.initialization(section_proxy)
89
90        # 呼び出しキーワード取り込み
91        self.commandword = self.getlist("commandword", fallback=self.default_commandword)
92
93        logging.trace("%s: %s", self.section, self)  # type: ignore

設定値取り込み

Arguments:
  • section_proxy (SectionProxy): 読み込み先(パーサー + セクション名)
def resolve_name(self, name: str) -> str:
 95    def resolve_name(self, name: str) -> str:
 96        """
 97        別名からメンバー名を逆引き
 98
 99        Args:
100            name (str): 変換する名前
101
102        Returns:
103            str: メンバー名(見つからない場合は空欄)
104
105        """
106        for x in self.info:
107            if name in x["alias"]:
108                return x["name"]
109
110        return ""

別名からメンバー名を逆引き

Arguments:
  • name (str): 変換する名前
Returns:

str: メンバー名(見つからない場合は空欄)

def alias(self, name: str) -> list[str]:
112    def alias(self, name: str) -> list[str]:
113        """
114        指定メンバーの別名をリストで返す
115
116        Args:
117            name (str): メンバー名
118
119        Returns:
120            list[str]: 別名リスト
121
122        """
123        for x in self.info:
124            if x.get("name") == name:
125                return x.get("alias")
126        return []

指定メンバーの別名をリストで返す

Arguments:
  • name (str): メンバー名
Returns:

list[str]: 別名リスト

lists: list[str]
128    @property
129    def lists(self) -> list[str]:
130        """メンバー名一覧をリストで返す"""
131        return [x.get("name") for x in self.info]

メンバー名一覧をリストで返す

all_lists: list[str]
133    @property
134    def all_lists(self) -> list[str]:
135        """
136        メンバー名、別名をすべてリストで返す
137
138        Returns:
139            list[str]: メンバー名、別名のリスト
140
141        """
142        ret: list[str] = []
143        for name in self.lists:
144            ret.append(name)
145            ret.extend(self.alias(name))
146
147        return list(set(ret))

メンバー名、別名をすべてリストで返す

Returns:

list[str]: メンバー名、別名のリスト

get_info: list[MemberDataDict]
149    @property
150    def get_info(self) -> list[MemberDataDict]:
151        """
152        全メンバー情報取得
153
154        Returns:
155            list[MemberDataDict]: メンバー情報
156
157        """
158        ret = g.params.read_data("MEMBER_INFO").to_dict(orient="records")
159        for row in ret:
160            row.update(alias=str(row["alias"]).split(","))
161
162        return cast(list[MemberDataDict], ret)

全メンバー情報取得

Returns:

list[MemberDataDict]: メンバー情報

def append(argument: list[str]) -> str:
165def append(argument: list[str]) -> str:
166    """
167    メンバー追加
168
169    Args:
170        argument (list[str]): 登録情報
171            - argument[0]: 登録するメンバー名
172            - argument[1]: 登録する別名
173
174    Returns:
175        str: 処理結果
176
177    """
178    resultdb = dbutil.connection(g.cfg.setting.database_file)
179
180    ret: bool = False
181    dbupdate_flg: bool = False
182    msg: str = "使い方が間違っています。"
183
184    if len(argument) == 1:  # 新規追加
185        new_name = textutil.str_conv(argument[0], textutil.ConversionType.HtoZ)
186        rows = resultdb.execute("select count() from member")
187        count = rows.fetchone()[0]
188        if count > g.cfg.member.registration_limit:
189            msg = "登録上限を超えています。"
190        else:  # 登録処理
191            ret, msg = validator.check_namepattern(new_name, "member")
192            if ret:
193                resultdb.execute(
194                    "insert into member(name) values (?)",
195                    (new_name,),
196                )
197                resultdb.execute(
198                    "insert into alias(name, member) values (?,?)",
199                    (new_name, new_name),
200                )
201                msg = f"「{new_name}」を登録しました。"
202                logging.info("add new member: %s", new_name)
203
204    if len(argument) == 2:  # 別名登録
205        new_name = textutil.str_conv(argument[0], textutil.ConversionType.HtoZ)
206        nic_name = textutil.str_conv(argument[1], textutil.ConversionType.HtoZ)
207        registration_flg = True
208        rows = resultdb.execute(
209            "select count() from alias where member=?",
210            (new_name,),
211        )
212        count = rows.fetchone()[0]
213        if count == 0:
214            msg = f"「{new_name}」はまだ登録されていません。"
215            registration_flg = False
216        if count > g.cfg.member.alias_limit:
217            msg = "登録上限を超えています。"
218            registration_flg = False
219
220        if registration_flg:  # 登録処理
221            ret, msg = validator.check_namepattern(nic_name, "member")
222            if ret:
223                resultdb.execute(
224                    "insert into alias(name, member) values (?,?)",
225                    (nic_name, new_name),
226                )
227                msg = f"「{new_name}」に「{nic_name}」を追加しました。"
228                logging.info("add alias: %s -> %s", new_name, nic_name)
229                dbupdate_flg = True
230
231        if dbupdate_flg:
232            rows = resultdb.execute(
233                """
234                select distinct name from (
235                    select p1_name as name from result
236                    union all select p2_name from result
237                    union all select p3_name from result
238                    union all select p4_name from result
239                    union all select name from remarks
240                );
241                """
242            )
243            name_list = [row["name"] for row in rows.fetchall()]
244
245            if {
246                nic_name,
247                textutil.str_conv(nic_name, textutil.ConversionType.KtoH),
248                textutil.str_conv(nic_name, textutil.ConversionType.HtoK),
249            } & set(name_list):
250                msg += modify.db_backup()
251                for tbl, col in [("result", f"p{x}_name") for x in range(1, 5)] + [("remarks", "name")]:
252                    resultdb.execute(
253                        f"update {tbl} set {col}=? where {col}=?",
254                        (new_name, nic_name),
255                    )
256                    resultdb.execute(
257                        f"update {tbl} set {col}=? where {col}=?",
258                        (new_name, textutil.str_conv(nic_name, textutil.ConversionType.KtoH)),
259                    )
260                    resultdb.execute(
261                        f"update {tbl} set {col}=? where {col}=?",
262                        (new_name, textutil.str_conv(nic_name, textutil.ConversionType.HtoK)),
263                    )
264                msg += "\nデータベースを更新しました。"
265
266    resultdb.commit()
267    resultdb.close()
268
269    g.cfg.member.info = g.cfg.member.get_info
270
271    return msg

メンバー追加

Arguments:
  • argument (list[str]): 登録情報
    • argument[0]: 登録するメンバー名
    • argument[1]: 登録する別名
Returns:

str: 処理結果

def remove(argument: list[str]) -> str:
274def remove(argument: list[str]) -> str:
275    """
276    メンバー削除
277
278    Args:
279        argument (list[str]): 削除情報
280            - argument[0]: 削除するメンバー名
281            - argument[1]: 削除する別名
282
283    Returns:
284        str: 処理結果
285
286    """
287    resultdb = dbutil.connection(g.cfg.setting.database_file)
288    msg = "使い方が間違っています。"
289
290    if len(argument) == 1:  # メンバー削除
291        new_name = textutil.str_conv(argument[0], textutil.ConversionType.HtoZ)
292        if new_name in g.cfg.member.lists:
293            resultdb.execute(
294                "delete from member where name=?",
295                (new_name,),
296            )
297            resultdb.execute(
298                "delete from alias where member=?",
299                (new_name,),
300            )
301            msg = f"「{new_name}」を削除しました。"
302            logging.info("remove member: %s", new_name)
303        else:
304            msg = f"「{new_name}」は登録されていません。"
305
306    if len(argument) == 2:  # 別名削除
307        new_name = textutil.str_conv(argument[0], textutil.ConversionType.HtoZ)
308        nic_name = textutil.str_conv(argument[1], textutil.ConversionType.HtoZ)
309        if nic_name in g.cfg.member.lists:
310            resultdb.execute(
311                "delete from alias where name=? and member=?",
312                (nic_name, new_name),
313            )
314            msg = f"「{new_name}」から「{nic_name}」を削除しました。"
315            logging.info("alias remove: %s -> %s", new_name, nic_name)
316        else:
317            msg = f"「{new_name}」に「{nic_name}」は登録されていません。"
318
319    resultdb.commit()
320    resultdb.close()
321
322    g.cfg.member.info = g.cfg.member.get_info
323
324    return msg

メンバー削除

Arguments:
  • argument (list[str]): 削除情報
    • argument[0]: 削除するメンバー名
    • argument[1]: 削除する別名
Returns:

str: 処理結果