lockbot 2.9.0__tar.gz → 2.9.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. {lockbot-2.9.0/python/lockbot.egg-info → lockbot-2.9.1}/PKG-INFO +1 -1
  2. {lockbot-2.9.0 → lockbot-2.9.1}/pyproject.toml +1 -1
  3. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/bots/schemas.py +4 -0
  4. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/base_bot.py +68 -0
  5. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/device_bot.py +4 -1
  6. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/handler.py +2 -0
  7. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/i18n/en.py +6 -0
  8. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/i18n/zh.py +6 -0
  9. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/node_bot.py +7 -2
  10. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/queue_bot.py +10 -4
  11. {lockbot-2.9.0 → lockbot-2.9.1/python/lockbot.egg-info}/PKG-INFO +1 -1
  12. {lockbot-2.9.0 → lockbot-2.9.1}/LICENSE +0 -0
  13. {lockbot-2.9.0 → lockbot-2.9.1}/MANIFEST.in +0 -0
  14. {lockbot-2.9.0 → lockbot-2.9.1}/README.md +0 -0
  15. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/__init__.py +0 -0
  16. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/__init__.py +0 -0
  17. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/__init__.py +0 -0
  18. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/admin/__init__.py +0 -0
  19. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/admin/router.py +0 -0
  20. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/audit/__init__.py +0 -0
  21. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/audit/models.py +0 -0
  22. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/audit/router.py +0 -0
  23. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/audit/service.py +0 -0
  24. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/auth/__init__.py +0 -0
  25. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/auth/dependencies.py +0 -0
  26. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/auth/models.py +0 -0
  27. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/auth/router.py +0 -0
  28. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/auth/schemas.py +0 -0
  29. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/backup/__init__.py +0 -0
  30. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/backup/router.py +0 -0
  31. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/backup/scheduler.py +0 -0
  32. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/backup/service.py +0 -0
  33. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/bots/__init__.py +0 -0
  34. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/bots/encryption.py +0 -0
  35. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/bots/manager.py +0 -0
  36. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/bots/models.py +0 -0
  37. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/bots/router.py +0 -0
  38. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/bots/webhook_handler.py +0 -0
  39. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/config.py +0 -0
  40. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/database.py +0 -0
  41. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/logs/__init__.py +0 -0
  42. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/main.py +0 -0
  43. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/rate_limit.py +0 -0
  44. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/settings/__init__.py +0 -0
  45. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/settings/models.py +0 -0
  46. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/backend/app/settings/router.py +0 -0
  47. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/__init__.py +0 -0
  48. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/bot_instance.py +0 -0
  49. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/config.py +0 -0
  50. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/device_usage_alert.py +0 -0
  51. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/device_usage_utils.py +0 -0
  52. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/entry.py +0 -0
  53. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/env.py +0 -0
  54. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/i18n/__init__.py +0 -0
  55. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/io.py +0 -0
  56. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/message_adapter.py +0 -0
  57. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/msg_utils.py +0 -0
  58. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/platforms/__init__.py +0 -0
  59. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/platforms/infoflow.py +0 -0
  60. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/request.py +0 -0
  61. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/scheduler.py +0 -0
  62. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot/core/utils.py +0 -0
  63. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot.egg-info/SOURCES.txt +0 -0
  64. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot.egg-info/dependency_links.txt +0 -0
  65. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot.egg-info/requires.txt +0 -0
  66. {lockbot-2.9.0 → lockbot-2.9.1}/python/lockbot.egg-info/top_level.txt +0 -0
  67. {lockbot-2.9.0 → lockbot-2.9.1}/setup.cfg +0 -0
  68. {lockbot-2.9.0 → lockbot-2.9.1}/tools/create_super_admin.py +0 -0
  69. {lockbot-2.9.0 → lockbot-2.9.1}/tools/gen_keys.py +0 -0
  70. {lockbot-2.9.0 → lockbot-2.9.1}/tools/reset_super_admin_password.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lockbot
3
- Version: 2.9.0
3
+ Version: 2.9.1
4
4
  Summary: Cluster resource management bot for IM platforms
5
5
  Author-email: Jianbang Yang <yangjianbang112@gmail.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "lockbot"
7
- version = "2.9.0"
7
+ version = "2.9.1"
8
8
  description = "Cluster resource management bot for IM platforms"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -68,6 +68,10 @@ def _validate_config_overrides(v: dict | None) -> dict | None:
68
68
  if show_alias is not None and not isinstance(show_alias, bool):
69
69
  errors.append("SHOW_NODE_ALIAS must be a boolean")
70
70
 
71
+ allow_alias = v.get("ALLOW_USER_ALIAS")
72
+ if allow_alias is not None and not isinstance(allow_alias, bool):
73
+ errors.append("ALLOW_USER_ALIAS must be a boolean")
74
+
71
75
  max_dur = v.get("MAX_LOCK_DURATION")
72
76
  default_dur = v.get("DEFAULT_DURATION")
73
77
  if isinstance(max_dur, int) and isinstance(default_dur, int) and max_dur != -1 and default_dur > max_dur:
@@ -133,6 +133,74 @@ class BaseLockBot:
133
133
  alias = aliases.get(node_key)
134
134
  return f"{node_key}「{alias}」" if alias else node_key
135
135
 
136
+ def alias(self, user_id, command):
137
+ """Set or clear a node alias. Usage: alias <node_key> [alias_value]"""
138
+ if not self.config.get_val("ALLOW_USER_ALIAS"):
139
+ return self.show_error(user_id, t("alias.disabled", config=self.config))
140
+
141
+ import re
142
+
143
+ m = re.match(r"^\s*alias\s+([\w\d_-]+)(?:\s+(.{1,15}))?\s*$", command)
144
+ if not m:
145
+ return self.show_error(user_id, t("alias.usage", config=self.config))
146
+
147
+ node_key = m.group(1)
148
+ alias_val = (m.group(2) or "").strip()
149
+
150
+ cluster_configs = self.config.get_val("CLUSTER_CONFIGS")
151
+ if node_key not in cluster_configs:
152
+ return self.show_error(
153
+ user_id,
154
+ t(
155
+ "alias.invalid_node",
156
+ config=self.config,
157
+ node_key=node_key,
158
+ valid_keys=str(list(cluster_configs.keys())),
159
+ ),
160
+ )
161
+
162
+ aliases = self.config.get_val("NODE_ALIASES") or {}
163
+ if alias_val:
164
+ aliases[node_key] = alias_val
165
+ else:
166
+ aliases.pop(node_key, None)
167
+ self.config.set_val("NODE_ALIASES", aliases)
168
+
169
+ # Persist to DB if running under platform mode
170
+ self._persist_config_override("NODE_ALIASES", aliases)
171
+
172
+ if alias_val:
173
+ self.logger.info("user=%s set alias %s -> %s", user_id, node_key, alias_val)
174
+ msg = t("alias.set_ok", config=self.config, node_key=node_key, alias=alias_val)
175
+ else:
176
+ self.logger.info("user=%s cleared alias %s", user_id, node_key)
177
+ msg = t("alias.clear_ok", config=self.config, node_key=node_key)
178
+ return self.adapter.build_reply(msg, [user_id])
179
+
180
+ def _persist_config_override(self, key, value):
181
+ """Persist a single config_override key to DB (best-effort)."""
182
+ try:
183
+ import json
184
+
185
+ from lockbot.backend.app.bots.models import Bot
186
+ from lockbot.backend.app.database import SessionLocal
187
+
188
+ bot_id = self.config.get_val("BOT_ID")
189
+ if not bot_id:
190
+ return
191
+ db = SessionLocal()
192
+ try:
193
+ bot = db.query(Bot).filter(Bot.id == int(bot_id)).first()
194
+ if bot:
195
+ overrides = json.loads(bot.config_overrides) if bot.config_overrides else {}
196
+ overrides[key] = value
197
+ bot.config_overrides = json.dumps(overrides, ensure_ascii=False)
198
+ db.commit()
199
+ finally:
200
+ db.close()
201
+ except Exception:
202
+ pass
203
+
136
204
  def _whitelist_hint(self):
137
205
  """Return whitelist hint string if BOT_OWNER is configured, else empty string."""
138
206
  owner = self.config.get_val("BOT_OWNER")
@@ -39,7 +39,7 @@ class DeviceBot(BaseLockBot):
39
39
  _loader = staticmethod(create_or_load_device_state)
40
40
 
41
41
  def supported_commands(self):
42
- return ["lock", "slock", "unlock", "free", "kickout", "help", "h", "query"]
42
+ return ["lock", "slock", "unlock", "free", "kickout", "help", "h", "query", "alias"]
43
43
 
44
44
  def parse_command(self, user_id, command_key, command, parsing_duration=False):
45
45
  """
@@ -493,6 +493,9 @@ class DeviceBot(BaseLockBot):
493
493
  text += t("help.query_node_example", config=self.config, node=example_node)
494
494
  text += "\n"
495
495
 
496
+ if self.config.get_val("ALLOW_USER_ALIAS"):
497
+ text += f"6. 备注: alias {example_node} <备注>\n\n"
498
+
496
499
  return text
497
500
 
498
501
  def _check_and_notify(self) -> float | None:
@@ -55,6 +55,8 @@ def execute_command(msg_data, bot):
55
55
  return bot.query(user_id)
56
56
  elif cmd in ("help", "h"):
57
57
  return bot.print_help(user_id)
58
+ elif cmd == "alias":
59
+ return bot.alias(user_id, rcv_info)
58
60
  else:
59
61
  return bot.print_help(user_id, t("error.unknown_error", config=getattr(bot, "config", None), command=rcv_info))
60
62
  return bot.print_help(user_id, t("error.unknown_error", config=getattr(bot, "config", None), command=rcv_info))
@@ -173,6 +173,12 @@ MESSAGES = {
173
173
  "opkick.invalid_format": "Invalid opkick format. Usage: opkick <username> [node] [dev x,y]",
174
174
  "opkick.notify_kicked": "⚠️ [Operator Release]\n\nNode: {node_key}\n",
175
175
  "opkick.notify_kicked_reason": "Reason: {reason}\n\n",
176
+ # ── Alias command ──
177
+ "alias.usage": "Usage: alias <node_key> [label]\nExample: alias node0 10.10.10.56\nClear: alias node0",
178
+ "alias.invalid_node": "Node {node_key} does not exist. Available: {valid_keys}\n",
179
+ "alias.set_ok": "✅ Set {node_key} alias to「{alias}」\n\n",
180
+ "alias.clear_ok": "✅ Cleared alias for {node_key}\n\n",
181
+ "alias.disabled": "User alias command is not enabled for this bot",
176
182
  # ── Webhook: bot not running ──
177
183
  "webhook.bot_not_running": "⚠️ Bot {bot_name}(ID:{bot_id}) is not running. " # noqa: E501
178
184
  "Please contact the owner @{owner_username} to start it.",
@@ -166,6 +166,12 @@ MESSAGES = {
166
166
  "opkick.invalid_format": "opkick命令格式错误,正确格式: opkick <username> [node] [dev x,y]",
167
167
  "opkick.notify_kicked": "⚠️【运维释放】\n\n节点: {node_key}\n",
168
168
  "opkick.notify_kicked_reason": "原因: {reason}\n\n",
169
+ # ── Alias command ──
170
+ "alias.usage": "用法: alias <节点名> [备注]\n示例: alias node0 10.10.10.56\n清除: alias node0",
171
+ "alias.invalid_node": "节点 {node_key} 不存在,可用节点: {valid_keys}\n",
172
+ "alias.set_ok": "✅ 已设置 {node_key} 备注为「{alias}」\n\n",
173
+ "alias.clear_ok": "✅ 已清除 {node_key} 的备注\n\n",
174
+ "alias.disabled": "该机器人未开启用户自助设置备注功能",
169
175
  # ── Webhook: bot not running ──
170
176
  "webhook.bot_not_running": (
171
177
  "⚠️ 机器人 {bot_name}(ID:{bot_id}) 尚未启动,请联系管理人 @{owner_username} 启动后再使用。"
@@ -37,7 +37,7 @@ class NodeBot(BaseLockBot):
37
37
  _loader = staticmethod(create_or_load_node_state)
38
38
 
39
39
  def supported_commands(self):
40
- return ["lock", "slock", "unlock", "free", "kickout", "help", "h", "query"]
40
+ return ["lock", "slock", "unlock", "free", "kickout", "help", "h", "query", "alias"]
41
41
 
42
42
  def parse_command(self, user_id, command_key, command, parsing_duration=False):
43
43
  """
@@ -358,7 +358,12 @@ class NodeBot(BaseLockBot):
358
358
  reply_info += t("help.section4_title", config=self.config)
359
359
  reply_info += t("help.section5_title", config=self.config)
360
360
  reply_info += t("help.query_at_bot", config=self.config)
361
- reply_info += f" {example_node0}\n\n"
361
+ reply_info += f" {example_node0}\n"
362
+
363
+ if self.config.get_val("ALLOW_USER_ALIAS"):
364
+ reply_info += f"6. 备注: alias {example_node0} <备注>\n"
365
+
366
+ reply_info += "\n"
362
367
  return reply_info
363
368
 
364
369
  def _check_and_notify(self) -> float | None:
@@ -26,7 +26,7 @@ class QueueBot(NodeBot):
26
26
  """
27
27
 
28
28
  def supported_commands(self):
29
- return ["lock", "unlock", "free", "kickout", "kicklock", "help", "h", "book", "take", "query"]
29
+ return ["lock", "unlock", "free", "kickout", "kicklock", "help", "h", "book", "take", "query", "alias"]
30
30
 
31
31
  def lock(self, user_id, command):
32
32
  """
@@ -345,7 +345,12 @@ class QueueBot(NodeBot):
345
345
  parts.append(t("help.section_help_title_queue", config=self.config))
346
346
  parts.append(t("help.section_query_title_queue", config=self.config))
347
347
  parts.append(t("help.query_at_bot", config=self.config))
348
- parts.append(f" {example_node0}\n\n")
348
+ parts.append(f" {example_node0}\n")
349
+
350
+ if self.config.get_val("ALLOW_USER_ALIAS"):
351
+ parts.append(f"8. 备注: alias {example_node0} <备注>\n")
352
+
353
+ parts.append("\n")
349
354
  return "".join(parts)
350
355
 
351
356
  def _check_and_notify(self) -> float | None:
@@ -522,11 +527,12 @@ class QueueBot(NodeBot):
522
527
  usage_info = ""
523
528
  for node_key, node_status in nodes.items():
524
529
  if node_filter is None or node_key == node_filter:
530
+ display_name = self._display_node(node_key)
525
531
  if node_status["status"] == "idle":
526
- usage_info += "{:} {}\n".format(node_key, t("status.idle", config=self.config))
532
+ usage_info += "{:} {}\n".format(display_name, t("status.idle", config=self.config))
527
533
  else:
528
534
  for user_idx, user_info in enumerate(node_status["current_users"]):
529
- node_name = f"{node_key}" if user_idx == 0 else ""
535
+ node_name = f"{display_name}" if user_idx == 0 else ""
530
536
  uid = user_info["user_id"]
531
537
  duration = format_duration(
532
538
  remaining_duration(user_info["start_time"], user_info["duration"]),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lockbot
3
- Version: 2.9.0
3
+ Version: 2.9.1
4
4
  Summary: Cluster resource management bot for IM platforms
5
5
  Author-email: Jianbang Yang <yangjianbang112@gmail.com>
6
6
  License: MIT
File without changes
File without changes
File without changes
File without changes
File without changes