feat: channel ownership rule — owner-presence means private, admin promote/demote
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NfPpSpccTWBfZg1FTveyaU
This commit is contained in:
+15
-17
@@ -20,6 +20,7 @@ from . import users as users_mod
|
||||
from . import oauth as oauth_mod
|
||||
from . import ws as ws_mod
|
||||
from . import configio as configio_mod
|
||||
from . import config_access
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -1407,19 +1408,13 @@ async def start(
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
def _visible_channels_for_user(user):
|
||||
"""Return {name: cfg} of channels visible to user (public + own private)."""
|
||||
"""Return {name: cfg} of channels visible to user (global + own)."""
|
||||
all_channels = config.get("notification_channels") or {}
|
||||
if user is None:
|
||||
return {}
|
||||
if user.admin:
|
||||
return dict(all_channels)
|
||||
visible = {}
|
||||
for name, cfg in all_channels.items():
|
||||
if not isinstance(cfg, dict):
|
||||
continue
|
||||
if not cfg.get("private") or cfg.get("owner") == user.username:
|
||||
visible[name] = cfg
|
||||
return visible
|
||||
return config_access.user_channels(all_channels, user.username)
|
||||
|
||||
def _build_channel_response(ch_name, ch_cfg):
|
||||
"""Serialize a channel config dict for the API response."""
|
||||
@@ -1443,7 +1438,7 @@ async def start(
|
||||
"type": ch_type,
|
||||
"type_label": settings_mod._CHANNEL_TYPE_LABELS.get(ch_type, ch_type.title()),
|
||||
"owner": ch_cfg.get("owner"),
|
||||
"private": bool(ch_cfg.get("private", False)),
|
||||
"private": not config_access.is_global(ch_cfg),
|
||||
"min_level": ch_cfg.get("min_level", "WARNING"),
|
||||
"fields": fields,
|
||||
}
|
||||
@@ -1508,9 +1503,12 @@ async def start(
|
||||
|
||||
if body.get("min_level"):
|
||||
channel_cfg["min_level"] = body["min_level"]
|
||||
channel_cfg["owner"] = user.username
|
||||
if body.get("private"):
|
||||
channel_cfg["private"] = True
|
||||
if user.admin:
|
||||
owner = (body.get("owner") or "").strip()
|
||||
if owner:
|
||||
channel_cfg["owner"] = owner
|
||||
else:
|
||||
channel_cfg["owner"] = user.username
|
||||
|
||||
try:
|
||||
disk_data = configio_mod.read_roundtrip(_config_path)
|
||||
@@ -1575,12 +1573,12 @@ async def start(
|
||||
|
||||
if body.get("min_level"):
|
||||
channel_cfg["min_level"] = body["min_level"]
|
||||
if owner is not None:
|
||||
if user.admin:
|
||||
new_owner = (body.get("owner") or "").strip() if "owner" in body else (owner or "")
|
||||
if new_owner:
|
||||
channel_cfg["owner"] = new_owner
|
||||
elif owner is not None:
|
||||
channel_cfg["owner"] = owner
|
||||
if "private" in body:
|
||||
channel_cfg["private"] = bool(body["private"])
|
||||
elif existing_on_disk.get("private"):
|
||||
channel_cfg["private"] = True
|
||||
|
||||
configio_mod.apply_channel(disk_data, ch_name, channel_cfg)
|
||||
configio_mod.write_config(_config_path, disk_data)
|
||||
|
||||
Reference in New Issue
Block a user