Extend the notification system with a third channel (telegram) alongside existing in_app and push channels. Add `telegram_enabled` column to `notification_preferences` table, update `NOTIFICATION_CHANNELS` and `_NOTIFICATION_CHANNEL_COLUMNS` mappings, and set telegram default to off (`_NOTIFICATION_CHANNEL_DEFAULTS`). Create `telegram_outbox` table with columns for uid, user_uid, chat_id, text, status, attempts, created_at, and sent_at, plus an index on status/id for efficient polling. Register `TelegramOutboxService` in the service manager lifecycle. Update API documentation strings to describe the new channel and its pairing requirement. Extend admin notification defaults view to include telegram column. Pass `notif_telegram_paired` flag to profile template based on `telegram_store.is_paired()` check. Update `NotificationPrefForm` and `NotificationDefaultForm` model literals to accept "telegram" as a valid channel value.
90 lines
3.2 KiB
JavaScript
90 lines
3.2 KiB
JavaScript
// retoor <retoor@molodetz.nl>
|
|
|
|
import { Http } from "./Http.js";
|
|
|
|
class TelegramPairing {
|
|
constructor(pubsub) {
|
|
this.root = document.querySelector("[data-telegram-pairing]");
|
|
if (!this.root) return;
|
|
this.pubsub = pubsub;
|
|
this.username = this.root.dataset.username;
|
|
this.statusLabel = this.root.querySelector("[data-telegram-status]");
|
|
this.requestBtn = this.root.querySelector("[data-telegram-request]");
|
|
this.unpairBtn = this.root.querySelector("[data-telegram-unpair]");
|
|
this.codeBox = this.root.querySelector("[data-telegram-code]");
|
|
this.codeValue = this.root.querySelector("[data-telegram-code-value]");
|
|
this.codeHint = this.root.querySelector("[data-telegram-code-hint]");
|
|
this.message = this.root.querySelector("[data-telegram-status-msg]");
|
|
if (this.requestBtn) this.requestBtn.addEventListener("click", () => this.request());
|
|
if (this.unpairBtn) this.unpairBtn.addEventListener("click", () => this.unpair());
|
|
this.subscribe();
|
|
}
|
|
|
|
subscribe() {
|
|
const uid = document.body.dataset.userUid || "";
|
|
if (!uid || !this.pubsub) return;
|
|
this.pubsub.subscribe(`user.${uid}.telegram`, (data) => {
|
|
if (data && data.paired) this.onPaired();
|
|
});
|
|
}
|
|
|
|
onPaired() {
|
|
this.setPaired(true);
|
|
this.hideCode();
|
|
this.setMessage("Telegram connected.", "success");
|
|
}
|
|
|
|
async request() {
|
|
this.requestBtn.disabled = true;
|
|
this.setMessage("Requesting...", "");
|
|
try {
|
|
const data = await Http.send(`/profile/${this.username}/telegram`, { action: "request" });
|
|
this.showCode(data.code, data.ttl_minutes);
|
|
this.setMessage("Send this code to the bot on Telegram", "success");
|
|
} catch (error) {
|
|
this.setMessage("Could not request a code", "error");
|
|
} finally {
|
|
this.requestBtn.disabled = false;
|
|
}
|
|
}
|
|
|
|
async unpair() {
|
|
this.unpairBtn.disabled = true;
|
|
this.setMessage("Disconnecting...", "");
|
|
try {
|
|
await Http.send(`/profile/${this.username}/telegram`, { action: "unpair" });
|
|
this.setPaired(false);
|
|
this.hideCode();
|
|
this.setMessage("Telegram disconnected", "success");
|
|
} catch (error) {
|
|
this.setMessage("Could not disconnect", "error");
|
|
} finally {
|
|
this.unpairBtn.disabled = false;
|
|
}
|
|
}
|
|
|
|
showCode(code, ttlMinutes) {
|
|
if (this.codeValue) this.codeValue.textContent = code;
|
|
if (this.codeHint) this.codeHint.textContent = `Valid for ${ttlMinutes} minutes. Open the Telegram bot and send it this code.`;
|
|
if (this.codeBox) this.codeBox.hidden = false;
|
|
}
|
|
|
|
hideCode() {
|
|
if (this.codeBox) this.codeBox.hidden = true;
|
|
}
|
|
|
|
setPaired(paired) {
|
|
if (this.statusLabel) this.statusLabel.textContent = paired ? "Connected" : "Not connected";
|
|
if (this.unpairBtn) this.unpairBtn.hidden = !paired;
|
|
}
|
|
|
|
setMessage(text, type) {
|
|
if (!this.message) return;
|
|
this.message.textContent = text;
|
|
this.message.dataset.state = type;
|
|
}
|
|
}
|
|
|
|
window.TelegramPairing = TelegramPairing;
|
|
export { TelegramPairing };
|