Improve management command output and add user link pills to search output (ref #7)

This commit is contained in:
Tulir Asokan
2017-11-25 15:06:02 +02:00
parent 69db7c8192
commit 77a2705dd9
3 changed files with 61 additions and 31 deletions
+13 -4
View File
@@ -98,8 +98,15 @@ class MautrixTelegram {
* @returns {Intent} The Matrix puppet intent for the given Telegram user. * @returns {Intent} The Matrix puppet intent for the given Telegram user.
*/ */
getIntentForTelegramUser(id) { getIntentForTelegramUser(id) {
return this.bridge.getIntentFromLocalpart( return this.bridge.getIntentFromLocalpart(this.getUsernameForTelegramUser(id))
this.config.bridge.username_template.replace("${ID}", id)) }
getUsernameForTelegramUser(id) {
return this.config.bridge.username_template.replace("${ID}", id)
}
getMatrixToLinkForTelegramUser(id) {
return `https://matrix.to/#/@${this.getUsernameForTelegramUser(id)}:${this.config.homeserver.domain}`
} }
/** /**
@@ -340,11 +347,13 @@ class MautrixTelegram {
commands.run(user, command, args, commands.run(user, command, args,
(reply, { allowHTML = false, markdown = true } = {}) => { (reply, { allowHTML = false, markdown = true } = {}) => {
reply = reply.replace("$cmdprefix", cmdprefix) reply = reply.replace("$cmdprefix", cmdprefix)
if (!allowHTML) { if (!markdown && !allowHTML) {
reply = escapeHTML(reply) reply = escapeHTML(reply)
} }
if (markdown) { if (markdown) {
reply = marked(reply) reply = marked(reply, {
sanitize: allowHTML,
})
} }
this.botIntent.sendMessage( this.botIntent.sendMessage(
evt.room_id, { evt.room_id, {
+42 -22
View File
@@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
const makePasswordHash = require("telegram-mtproto").plugins.makePasswordHash const makePasswordHash = require("telegram-mtproto").plugins.makePasswordHash
const escapeHTML = require("escape-html")
const commands = {} const commands = {}
@@ -30,7 +29,7 @@ function run(sender, command, args, reply, app) {
args.unshift(command) args.unshift(command)
return sender.commandStatus.next(sender, args, reply, app) return sender.commandStatus.next(sender, args, reply, app)
} }
reply("Unknown command. Try \"$cmdprefix help\" for help.") reply("Unknown command. Try `$cmdprefix help` for help.")
return undefined return undefined
} }
try { try {
@@ -38,10 +37,11 @@ function run(sender, command, args, reply, app) {
} catch (err) { } catch (err) {
reply(`Error running command: ${err}.`) reply(`Error running command: ${err}.`)
if (err instanceof Error) { if (err instanceof Error) {
reply("Check bridge console for stack trace") reply(["```", err.stack, "```"].join(""))
console.error(err.stack) console.error(err.stack)
} }
} }
return undefined
} }
commands.cancel = () => "Nothing to cancel." commands.cancel = () => "Nothing to cancel."
@@ -56,7 +56,7 @@ commands.help = (sender, args, reply) => {
**logout** - Log out from Telegram. Currently broken. **logout** - Log out from Telegram. Currently broken.
**api** <_method_> <_args_> - Call a Telegram API method. Args is always a JSON object. Disabled by default. **api** <_method_> <_args_> - Call a Telegram API method. Args is always a JSON object. Disabled by default.
`, {allowHTML: true}) `, { allowHTML: true })
} }
@@ -69,7 +69,7 @@ commands.help = (sender, args, reply) => {
*/ */
commands.enterPassword = async (sender, args, reply) => { commands.enterPassword = async (sender, args, reply) => {
if (args.length === 0) { if (args.length === 0) {
reply("Usage: $cmdprefix <password>") reply("**Usage:** `$cmdprefix <password>`")
return return
} }
@@ -79,8 +79,11 @@ commands.enterPassword = async (sender, args, reply) => {
reply(`Logged in successfully as @${sender.telegramPuppet.getDisplayName()}.`) reply(`Logged in successfully as @${sender.telegramPuppet.getDisplayName()}.`)
sender.commandStatus = undefined sender.commandStatus = undefined
} catch (err) { } catch (err) {
reply(`Login failed: ${err}`) reply(`**Login failed:** ${err}`)
console.log(err) if (err instanceof Error) {
reply(["```", err.stack, "```"].join(""))
console.error(err.stack)
}
} }
} }
@@ -89,7 +92,7 @@ commands.enterPassword = async (sender, args, reply) => {
*/ */
commands.enterCode = async (sender, args, reply) => { commands.enterCode = async (sender, args, reply) => {
if (args.length === 0) { if (args.length === 0) {
reply("Usage: $cmdprefix <authentication code>") reply("**Usage:** `$cmdprefix <authentication code>`")
return return
} }
@@ -100,7 +103,7 @@ commands.enterCode = async (sender, args, reply) => {
sender.commandStatus = undefined sender.commandStatus = undefined
} else if (data.status === "need-password") { } else if (data.status === "need-password") {
reply(`You have two-factor authentication enabled. Password hint: ${data.hint} reply(`You have two-factor authentication enabled. Password hint: ${data.hint}
Enter your password using "$cmdprefix <password>"`) Enter your password using \`$cmdprefix <password>\``)
sender.commandStatus = { sender.commandStatus = {
action: "Two-factor authentication", action: "Two-factor authentication",
next: commands.enterPassword, next: commands.enterPassword,
@@ -111,8 +114,11 @@ Enter your password using "$cmdprefix <password>"`)
} }
} catch (err) { } catch (err) {
// TODO login fails somewhere with TypeError: Cannot read property 'status' of undefined // TODO login fails somewhere with TypeError: Cannot read property 'status' of undefined
reply(`Login failed: ${err}`) reply(`**Login failed:** ${err}`)
console.error(err.stack) if (err instanceof Error) {
reply(["```", err.stack, "```"].join(""))
console.error(err.stack)
}
} }
} }
@@ -121,7 +127,7 @@ Enter your password using "$cmdprefix <password>"`)
*/ */
commands.login = async (sender, args, reply) => { commands.login = async (sender, args, reply) => {
if (args.length === 0) { if (args.length === 0) {
reply("Usage: $cmdprefix login <phone number>") reply("**Usage:** `$cmdprefix login <phone number>`")
return return
} }
@@ -134,8 +140,11 @@ commands.login = async (sender, args, reply) => {
next: commands.enterCode, next: commands.enterCode,
} }
} catch (err) { } catch (err) {
reply(`Failed to send code: ${err}`) reply(`**Failed to send code:** ${err}`)
console.log(err) if (err instanceof Error) {
reply(["```", err.stack, "```"].join(""))
console.error(err.stack)
}
} }
} }
@@ -148,7 +157,11 @@ commands.logout = async (sender, args, reply) => {
sender.logOutFromTelegram() sender.logOutFromTelegram()
reply("Logged out successfully.") reply("Logged out successfully.")
} catch (err) { } catch (err) {
reply(`Failed to log out: ${err}`) reply(`**Failed to log out:** ${err}`)
if (err instanceof Error) {
reply(["```", err.stack, "```"].join(""))
console.error(err.stack)
}
} }
} }
@@ -165,10 +178,11 @@ commands.search = async (sender, args, reply, app) => {
if (args[0] !== "-r" && args[0] !== "--remote") { if (args[0] !== "-r" && args[0] !== "--remote") {
const contactResults = await sender.searchContacts(args.join(" ")) const contactResults = await sender.searchContacts(args.join(" "))
if (contactResults.length > 0) { if (contactResults.length > 0) {
msg.push("Following results found from local contacts:") msg.push("**Following results found from local contacts:**")
msg.push("") msg.push("")
for (const {match, contact} of contactResults) { for (const { match, contact } of contactResults) {
msg.push(`- ${contact.getDisplayName()}: ${contact.id} (${match}% match)`) msg.push(`- <a href="${
app.getMatrixToLinkForTelegramUser(contact.id)}">${contact.getDisplayName()}</a>: ${contact.id} (${match}% match)`)
} }
msg.push("") msg.push("")
msg.push("To force searching from Telegram servers, add `-r` before the search query.") msg.push("To force searching from Telegram servers, add `-r` before the search query.")
@@ -180,14 +194,20 @@ commands.search = async (sender, args, reply, app) => {
msg.push("-r flag found: forcing remote search") msg.push("-r flag found: forcing remote search")
msg.push("") msg.push("")
} }
const telegramResults = await sender.searchTelegram(args.join(" ")) const query = args.join(" ")
if (query.length < 5) {
reply("Failed to search server: Query is too short.")
return
}
const telegramResults = await sender.searchTelegram(query)
if (telegramResults.length > 0) { if (telegramResults.length > 0) {
msg.push("Following results received from Telegram server:") msg.push("**Following results received from Telegram server:**")
for (const user of telegramResults) { for (const user of telegramResults) {
msg.push(`- ${user.getDisplayName()}: ${user.id}`) msg.push(`- <a href="${
app.getMatrixToLinkForTelegramUser(user.id)}">${user.getDisplayName()}</a>: ${user.id}`)
} }
} else { } else {
msg.push("No users found.") msg.push("**No users found.**")
} }
reply(msg.join("\n")) reply(msg.join("\n"))
} }
+6 -5
View File
@@ -16,7 +16,7 @@
const md5 = require("md5") const md5 = require("md5")
const TelegramPuppet = require("./telegram-puppet") const TelegramPuppet = require("./telegram-puppet")
const TelegramPeer = require("./telegram-peer") const TelegramPeer = require("./telegram-peer")
const strSim = require("string-similarity"); const strSim = require("string-similarity")
/** /**
* MatrixUser represents a Matrix user who probably wants to control their * MatrixUser represents a Matrix user who probably wants to control their
@@ -139,10 +139,12 @@ class MatrixUser {
return changed return changed
} }
async searchContacts(query, {maxResults=5, minSimilarity = 0.45} = {}) { async searchContacts(query, { maxResults = 5, minSimilarity = 0.45 } = {}) {
const results = [] const results = []
for (const contact of this.contacts) { for (const contact of this.contacts) {
let displaynameSimilarity = 0, usernameSimilarity = 0, numberSimilarity = 0 let displaynameSimilarity = 0
let usernameSimilarity = 0
let numberSimilarity = 0
if (contact.firstName || contact.lastName) { if (contact.firstName || contact.lastName) {
displaynameSimilarity = strSim.compareTwoStrings(query, contact.getFirstAndLastName()) displaynameSimilarity = strSim.compareTwoStrings(query, contact.getFirstAndLastName())
} }
@@ -153,7 +155,6 @@ class MatrixUser {
numberSimilarity = strSim.compareTwoStrings(query, contact.phoneNumber) numberSimilarity = strSim.compareTwoStrings(query, contact.phoneNumber)
} }
const similarity = Math.max(displaynameSimilarity, usernameSimilarity, numberSimilarity) const similarity = Math.max(displaynameSimilarity, usernameSimilarity, numberSimilarity)
console.log(contact.getDisplayName(), similarity, displaynameSimilarity, usernameSimilarity, numberSimilarity)
if (similarity >= minSimilarity) { if (similarity >= minSimilarity) {
results.push({ results.push({
similarity, similarity,
@@ -167,7 +168,7 @@ class MatrixUser {
.slice(0, maxResults) .slice(0, maxResults)
} }
async searchTelegram(query, {maxResults=5} = {}) { async searchTelegram(query, { maxResults = 5 } = {}) {
const results = await this.telegramPuppet.client("contacts.search", { const results = await this.telegramPuppet.client("contacts.search", {
q: query, q: query,
limit: maxResults, limit: maxResults,