Channels: default-only threading + automation (read-only) channels — threading (topic switcher, Ctrl+T, auto-threading) is now only active on the default channel, and the gateway ignores auto_thread for other channels; new channel.set_automation frame marks a channel read-only for cron/webhook output (app hides the composer behind a notice, gateway rejects message.send, default channel cannot be marked, flag syncs to all devices via the full-entry channel.renamed response, gear badge in the list); header pill drops the 'Bot' subtitle and shows the chat_id on automation channels (tap to copy for cron delivery targeting); also fixes a pre-existing stray brace that made frames.schema.json invalid JSON
This commit is contained in:
1 parent
d7cd59b685
commit
10e9565e2e
9 files changed
+256
-37
No files matched your search
@@ -67,7 +67,8 @@ class ChannelDirectory:
|
||||
created REAL NOT NULL DEFAULT 0,
|
||||
favorite INTEGER NOT NULL DEFAULT 0,
|
||||
icon TEXT,
|
||||
color TEXT
|
||||
color TEXT,
|
||||
automation INTEGER NOT NULL DEFAULT 0
|
||||
)
|
||||
"""
|
||||
)
|
||||
@@ -83,6 +84,10 @@ class ChannelDirectory:
|
||||
self._conn.execute("ALTER TABLE channels ADD COLUMN icon TEXT")
|
||||
if "color" not in existing:
|
||||
self._conn.execute("ALTER TABLE channels ADD COLUMN color TEXT")
|
||||
if "automation" not in existing:
|
||||
self._conn.execute(
|
||||
"ALTER TABLE channels ADD COLUMN automation INTEGER NOT NULL DEFAULT 0"
|
||||
)
|
||||
self._conn.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS counters (
|
||||
@@ -138,9 +143,12 @@ class ChannelDirectory:
|
||||
else:
|
||||
# Refresh the name only if it was never renamed by the user
|
||||
# (heuristic: still equals the previous default name is not
|
||||
# trackable, so leave user-renamed names alone).
|
||||
# trackable, so leave user-renamed names alone). The default
|
||||
# channel is the user's chat surface, so it is never an
|
||||
# automation channel.
|
||||
self._conn.execute(
|
||||
"UPDATE channels SET kind = ?, is_default = 1 WHERE chat_id = ?",
|
||||
"UPDATE channels SET kind = ?, is_default = 1, automation = 0 "
|
||||
"WHERE chat_id = ?",
|
||||
(KIND_DEFAULT, chat_id),
|
||||
)
|
||||
# Exactly one default: clear any other default flag.
|
||||
@@ -206,7 +214,11 @@ class ChannelDirectory:
|
||||
return self.get(chat_id)
|
||||
|
||||
def set_default(self, chat_id: str) -> Optional[Dict[str, Any]]:
|
||||
"""Mark *chat_id* as the default channel (clears the previous one)."""
|
||||
"""Mark *chat_id* as the default channel (clears the previous one).
|
||||
|
||||
The default channel is the user's chat surface, so the automation
|
||||
flag is cleared on it (a read-only home channel would be unusable).
|
||||
"""
|
||||
with self._lock:
|
||||
row = self._conn.execute(
|
||||
"SELECT 1 FROM channels WHERE chat_id = ? AND archived = 0",
|
||||
@@ -216,7 +228,9 @@ class ChannelDirectory:
|
||||
return None
|
||||
self._conn.execute("UPDATE channels SET is_default = 0")
|
||||
self._conn.execute(
|
||||
"UPDATE channels SET is_default = 1 WHERE chat_id = ?", (chat_id,)
|
||||
"UPDATE channels SET is_default = 1, automation = 0 "
|
||||
"WHERE chat_id = ?",
|
||||
(chat_id,),
|
||||
)
|
||||
self._conn.commit()
|
||||
return self.get(chat_id)
|
||||
@@ -250,6 +264,29 @@ class ChannelDirectory:
|
||||
return None
|
||||
return self.get(chat_id)
|
||||
|
||||
def set_automation(self, chat_id: str, on: bool) -> Optional[Dict[str, Any]]:
|
||||
"""Mark *chat_id* as an automation channel (or clear the flag).
|
||||
|
||||
Automation channels are read-only for the user: they only receive
|
||||
gateway-originated output (cron jobs, webhooks). The app hides the
|
||||
composer and the gateway rejects ``message.send`` into them. The
|
||||
default channel cannot be marked automation (it is the user's chat
|
||||
surface), so this returns ``None`` for it, like ``delete``.
|
||||
"""
|
||||
with self._lock:
|
||||
row = self._conn.execute(
|
||||
"SELECT is_default FROM channels WHERE chat_id = ? AND archived = 0",
|
||||
(chat_id,),
|
||||
).fetchone()
|
||||
if row is None or row["is_default"]:
|
||||
return None
|
||||
self._conn.execute(
|
||||
"UPDATE channels SET automation = ? WHERE chat_id = ?",
|
||||
(1 if on else 0, chat_id),
|
||||
)
|
||||
self._conn.commit()
|
||||
return self.get(chat_id)
|
||||
|
||||
def delete(self, chat_id: str) -> Optional[Dict[str, Any]]:
|
||||
"""Soft-delete (archive) a channel. History stays for search.
|
||||
|
||||
@@ -365,6 +402,7 @@ def _row_to_entry(row: sqlite3.Row) -> Dict[str, Any]:
|
||||
"favorite": bool(row["favorite"]),
|
||||
"icon": row["icon"],
|
||||
"color": row["color"],
|
||||
"automation": bool(row["automation"]),
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user