jj
This commit is contained in:
240
cmdnat/matrix.py
240
cmdnat/matrix.py
@@ -9,6 +9,7 @@ import uuid
|
||||
from urllib.parse import parse_qs, urlparse
|
||||
|
||||
from cmdlet._shared import Cmdlet, CmdletArg
|
||||
from SYS.config import load_config, save_config
|
||||
from SYS.logger import log, debug
|
||||
from SYS.result_table import Table
|
||||
from SYS import pipeline as ctx
|
||||
@@ -78,55 +79,43 @@ def _extract_set_value_arg(args: Sequence[str]) -> Optional[str]:
|
||||
|
||||
|
||||
def _update_matrix_config(config: Dict[str, Any], key: str, value: Any) -> bool:
|
||||
"""Update a Matrix config value and write to config file.
|
||||
|
||||
Returns True if successful, False otherwise.
|
||||
"""Update the Matrix provider block in the shared config.
|
||||
|
||||
This method writes to the unified config store so changes persist between
|
||||
sessions.
|
||||
"""
|
||||
try:
|
||||
from SYS.config import get_config_path
|
||||
from configparser import ConfigParser
|
||||
|
||||
if not isinstance(config, dict):
|
||||
return False
|
||||
|
||||
# Ensure provider.matrix section exists
|
||||
providers = config.get("provider", {})
|
||||
|
||||
value_str = str(value)
|
||||
|
||||
current_cfg = load_config() or {}
|
||||
providers = current_cfg.setdefault("provider", {})
|
||||
if not isinstance(providers, dict):
|
||||
providers = {}
|
||||
config["provider"] = providers
|
||||
|
||||
matrix_conf = providers.get("matrix", {})
|
||||
if not isinstance(matrix_conf, dict):
|
||||
matrix_conf = {}
|
||||
providers["matrix"] = matrix_conf
|
||||
|
||||
# Update the in-memory config
|
||||
matrix_conf[key] = value
|
||||
|
||||
# Try to write to config file using configparser
|
||||
try:
|
||||
config_path = get_config_path()
|
||||
if not config_path:
|
||||
return False
|
||||
|
||||
parser = ConfigParser()
|
||||
if Path(config_path).exists():
|
||||
parser.read(config_path)
|
||||
|
||||
section_name = "provider=matrix"
|
||||
if not parser.has_section(section_name):
|
||||
parser.add_section(section_name)
|
||||
|
||||
parser.set(section_name, key, str(value))
|
||||
|
||||
with open(config_path, "w") as f:
|
||||
parser.write(f)
|
||||
|
||||
return True
|
||||
except Exception as exc:
|
||||
debug(f"[matrix] Failed to write config file: {exc}")
|
||||
# Config was updated in memory at least
|
||||
return True
|
||||
current_cfg["provider"] = providers
|
||||
|
||||
matrix_cfg = providers.setdefault("matrix", {})
|
||||
if not isinstance(matrix_cfg, dict):
|
||||
matrix_cfg = {}
|
||||
providers["matrix"] = matrix_cfg
|
||||
|
||||
matrix_cfg[key] = value_str
|
||||
|
||||
save_config(current_cfg)
|
||||
|
||||
# Keep the supplied config dict in sync for the running CLI
|
||||
target_providers = config.setdefault("provider", {})
|
||||
if not isinstance(target_providers, dict):
|
||||
target_providers = {}
|
||||
config["provider"] = target_providers
|
||||
target_matrix = target_providers.setdefault("matrix", {})
|
||||
if not isinstance(target_matrix, dict):
|
||||
target_matrix = {}
|
||||
target_providers["matrix"] = target_matrix
|
||||
target_matrix[key] = value_str
|
||||
return True
|
||||
except Exception as exc:
|
||||
debug(f"[matrix] Failed to update Matrix config: {exc}")
|
||||
return False
|
||||
@@ -628,14 +617,14 @@ def _show_settings_table(config: Dict[str, Any]) -> int:
|
||||
|
||||
settings_items = []
|
||||
if isinstance(matrix_conf, dict):
|
||||
sensitive_keys = {"access_token", "password"}
|
||||
for key in sorted(matrix_conf.keys()):
|
||||
value = matrix_conf[key]
|
||||
# Skip sensitive/complex values
|
||||
if key in ("password",):
|
||||
value = "***"
|
||||
display_value = "***" if key in sensitive_keys else str(value)
|
||||
settings_items.append({
|
||||
"key": key,
|
||||
"value": str(value),
|
||||
"label": key,
|
||||
"value": display_value,
|
||||
"original_value": value,
|
||||
})
|
||||
|
||||
@@ -643,10 +632,19 @@ def _show_settings_table(config: Dict[str, Any]) -> int:
|
||||
log("No Matrix settings configured. Edit config.conf manually.", file=sys.stderr)
|
||||
return 0
|
||||
|
||||
settings_items.append({
|
||||
"action": "test",
|
||||
"label": "Test connection",
|
||||
"value": "Verify the homeserver and token before picking rooms",
|
||||
"description": "Runs a health check and then prompts for default rooms",
|
||||
})
|
||||
|
||||
for item in settings_items:
|
||||
row = table.add_row()
|
||||
row.add_column("Key", item["key"])
|
||||
row.add_column("Value", item["value"])
|
||||
label = item.get("label") or item.get("key") or "Setting"
|
||||
value_text = item.get("value") or item.get("description") or ""
|
||||
row.add_column("Key", label)
|
||||
row.add_column("Value", value_text)
|
||||
|
||||
ctx.set_last_result_table_overlay(table, settings_items)
|
||||
ctx.set_current_stage_table(table)
|
||||
@@ -712,6 +710,15 @@ def _handle_settings_edit(result: Any, args: Sequence[str], config: Dict[str, An
|
||||
return 1
|
||||
|
||||
selected_item = last_items[idx]
|
||||
selected_action = None
|
||||
if isinstance(selected_item, dict):
|
||||
selected_action = selected_item.get("action")
|
||||
else:
|
||||
selected_action = getattr(selected_item, "action", None)
|
||||
|
||||
if selected_action == "test":
|
||||
return _handle_settings_test(config)
|
||||
|
||||
key = None
|
||||
if isinstance(selected_item, dict):
|
||||
key = selected_item.get("key")
|
||||
@@ -742,6 +749,132 @@ def _handle_settings_edit(result: Any, args: Sequence[str], config: Dict[str, An
|
||||
return 1
|
||||
|
||||
|
||||
def _handle_settings_test(config: Dict[str, Any]) -> int:
|
||||
"""Test Matrix credentials and prompt for default rooms upon success."""
|
||||
from Provider.matrix import Matrix
|
||||
|
||||
try:
|
||||
provider = Matrix(config)
|
||||
except Exception as exc:
|
||||
log(f"Matrix test failed: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
log("Matrix configuration validated. Select default rooms to share.")
|
||||
return _show_default_room_picker(config, provider=provider)
|
||||
|
||||
|
||||
def _show_default_room_picker(config: Dict[str, Any], *, provider: Optional["Matrix"] = None) -> int:
|
||||
"""Display joined rooms so the user can select defaults for sharing."""
|
||||
from Provider.matrix import Matrix
|
||||
|
||||
try:
|
||||
if provider is None:
|
||||
provider = Matrix(config)
|
||||
except Exception as exc:
|
||||
log(f"Matrix not available: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try:
|
||||
rooms = provider.list_rooms()
|
||||
except Exception as exc:
|
||||
log(f"Failed to list Matrix rooms: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if not rooms:
|
||||
log("No joined rooms found.", file=sys.stderr)
|
||||
return 0
|
||||
|
||||
default_ids = {
|
||||
str(v).strip()
|
||||
for v in _parse_config_room_filter_ids(config)
|
||||
if str(v).strip()
|
||||
}
|
||||
|
||||
table = Table("Matrix Rooms (select defaults with @N)")
|
||||
table.set_table("matrix")
|
||||
table.set_source_command(".matrix", ["-settings"])
|
||||
|
||||
room_items: List[Dict[str, Any]] = []
|
||||
for room in rooms:
|
||||
if isinstance(room, dict):
|
||||
room_id = str(room.get("room_id") or "").strip()
|
||||
name = str(room.get("name") or "").strip()
|
||||
else:
|
||||
room_id = ""
|
||||
name = ""
|
||||
|
||||
row = table.add_row()
|
||||
row.add_column("Name", name)
|
||||
row.add_column("Room", room_id)
|
||||
row.add_column("Default", "✓" if room_id and room_id in default_ids else "")
|
||||
|
||||
room_items.append({
|
||||
**(room if isinstance(room, dict) else {}),
|
||||
"room_id": room_id,
|
||||
"name": name,
|
||||
"store": "matrix",
|
||||
"title": name or room_id or "Matrix Room",
|
||||
})
|
||||
|
||||
ctx.set_last_result_table_overlay(table, room_items)
|
||||
ctx.set_current_stage_table(table)
|
||||
ctx.set_pending_pipeline_tail([[".matrix", "-settings-rooms"]], ".matrix")
|
||||
log("Select default rooms to share (used by @N and autocomplete).")
|
||||
return 0
|
||||
|
||||
|
||||
def _handle_settings_rooms(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
|
||||
"""Store the selected rooms list as the default sharing target."""
|
||||
selection_indices = []
|
||||
try:
|
||||
selection_indices = ctx.get_last_selection() or []
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
last_items = []
|
||||
try:
|
||||
last_items = ctx.get_last_result_items() or []
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if not selection_indices or not last_items:
|
||||
log("No Matrix room selected. Use @N on the rooms table.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
room_ids: List[str] = []
|
||||
for idx in selection_indices:
|
||||
if not isinstance(idx, int):
|
||||
continue
|
||||
if idx < 0 or idx >= len(last_items):
|
||||
continue
|
||||
item = last_items[idx]
|
||||
candidate = None
|
||||
if isinstance(item, dict):
|
||||
candidate = item.get("room_id") or item.get("id")
|
||||
else:
|
||||
candidate = getattr(item, "room_id", None) or getattr(item, "id", None)
|
||||
if candidate:
|
||||
room_ids.append(str(candidate).strip())
|
||||
|
||||
cleaned: List[str] = []
|
||||
for rid in room_ids:
|
||||
clean = str(rid or "").strip()
|
||||
if clean and clean not in cleaned:
|
||||
cleaned.append(clean)
|
||||
|
||||
if not cleaned:
|
||||
log("No valid Matrix room selected.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
value = ", ".join(cleaned)
|
||||
if not _update_matrix_config(config, "rooms", value):
|
||||
log("✗ Failed to save default rooms", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
log(f"✓ Default rooms saved: {value}")
|
||||
return _show_settings_table(config)
|
||||
|
||||
|
||||
def _show_rooms_table(config: Dict[str, Any]) -> int:
|
||||
"""Display rooms (refactored original behavior)."""
|
||||
from Provider.matrix import Matrix
|
||||
@@ -855,6 +988,9 @@ def _run(result: Any, args: Sequence[str], config: Dict[str, Any]) -> int:
|
||||
if _has_flag(args, "-settings-edit"):
|
||||
return _handle_settings_edit(result, args, config)
|
||||
|
||||
if _has_flag(args, "-settings-rooms"):
|
||||
return _handle_settings_rooms(result, args, config)
|
||||
|
||||
# Internal stage: send previously selected items to selected rooms.
|
||||
if _has_flag(args, "-send"):
|
||||
# Ensure we don't re-print the rooms picker table on the send stage.
|
||||
@@ -1031,6 +1167,12 @@ CMDLET = Cmdlet(
|
||||
description="(internal) Handle settings modification",
|
||||
required=False,
|
||||
),
|
||||
CmdletArg(
|
||||
name="settings-rooms",
|
||||
type="bool",
|
||||
description="(internal) Save selected default rooms",
|
||||
required=False,
|
||||
),
|
||||
CmdletArg(
|
||||
name="set-value",
|
||||
type="string",
|
||||
|
||||
Reference in New Issue
Block a user