Implement room and user creation
This commit is contained in:
+23
-5
@@ -135,11 +135,29 @@ commands.logout = async (sender, args, reply) => {
|
||||
const TelegramPeer = require("./telegram-peer")
|
||||
const Portal = require("./portal")
|
||||
|
||||
commands.test = async (sender, args, reply, app) => {
|
||||
const peer = new TelegramPeer(args[0], +args[1])
|
||||
const hashFound = await peer.getAccessHash(app, sender.telegramPuppet)
|
||||
reply("Access hash found: " + hashFound)
|
||||
new Portal(app, "", peer).createMatrixRoom(sender.telegramPuppet)
|
||||
commands.createRoom = async (sender, args, reply, app) => {
|
||||
let peer = new TelegramPeer(args[0], +args[1])
|
||||
const portal = await app.getPortalByPeer(peer)
|
||||
const roomID = await portal.createMatrixRoom(sender.telegramPuppet)
|
||||
if (!roomID) {
|
||||
reply("Failed to create room.")
|
||||
return
|
||||
}
|
||||
await app.botIntent.invite(roomID, sender.userID)
|
||||
reply(`Created room ${roomID} and invited ${sender.userID}`)
|
||||
}
|
||||
|
||||
commands.syncUsers = async (sender, args, reply, app) => {
|
||||
let peer = new TelegramPeer(args[0], +args[1])
|
||||
const portal = await app.getPortalByPeer(peer)
|
||||
try {
|
||||
await portal.syncTelegramUsers(sender.telegramPuppet)
|
||||
reply("Users synchronized successfully.")
|
||||
} catch (err) {
|
||||
reply(`Failed to sync users: ${err}`)
|
||||
console.error(err)
|
||||
console.error(err.stack)
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
+2
-5
@@ -104,9 +104,7 @@ class MatrixUser {
|
||||
}
|
||||
for (const [index, contact] of Object.entries(contacts.users)) {
|
||||
const telegramUser = await this.app.getTelegramUser(contact.id)
|
||||
if (telegramUser.updateInfo(this.telegramPuppet, contact)) {
|
||||
telegramUser.save()
|
||||
}
|
||||
await telegramUser.updateInfo(this.telegramPuppet, contact)
|
||||
contacts.users[index] = telegramUser
|
||||
}
|
||||
this.contacts = contacts.users
|
||||
@@ -123,8 +121,7 @@ class MatrixUser {
|
||||
}
|
||||
const peer = new TelegramPeer(dialog._, dialog.id)
|
||||
const portal = await this.app.getPortalByPeer(peer)
|
||||
if (portal.updateInfo(this.telegramPuppet, dialog)) {
|
||||
portal.save()
|
||||
if (await portal.updateInfo(this.telegramPuppet, dialog)) {
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
|
||||
+24
-12
@@ -41,14 +41,24 @@ class Portal {
|
||||
return portal
|
||||
}
|
||||
|
||||
async syncParticipants(participants) {
|
||||
for (const participant of participants) {
|
||||
const user = this.app.getTelegramUser(participant.id)
|
||||
if (user.updateInfo(participant)) {
|
||||
user.save()
|
||||
async syncTelegramUsers(telegramPOV, users) {
|
||||
if (!users) {
|
||||
if (! await this.loadAccessHash(telegramPOV)) {
|
||||
return false
|
||||
}
|
||||
user.intent.join(this.roomID)
|
||||
const data = await this.peer.getInfo(telegramPOV)
|
||||
users = data.users
|
||||
}
|
||||
for (const userData of users) {
|
||||
const user = await this.app.getTelegramUser(userData.id)
|
||||
await user.updateInfo(telegramPOV, userData)
|
||||
await user.intent.join(this.roomID)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
loadAccessHash(telegramPOV) {
|
||||
return this.peer.loadAccessHash(this.app, telegramPOV, {portal: this})
|
||||
}
|
||||
|
||||
handleMatrixEvent(evt) {
|
||||
@@ -62,9 +72,11 @@ class Portal {
|
||||
}
|
||||
|
||||
try {
|
||||
const {info, participants} = await this.peer.getInfo(telegramPOV)
|
||||
console.log(JSON.stringify(info, "", " "))
|
||||
console.log(JSON.stringify(participants, "", " "))
|
||||
if (! await this.loadAccessHash(telegramPOV)) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const {info, users} = await this.peer.getInfo(telegramPOV)
|
||||
|
||||
const room = await this.app.botIntent.createRoom({
|
||||
options: {
|
||||
@@ -77,7 +89,7 @@ class Portal {
|
||||
this.app.portalsByRoomID.set(this.roomID, this)
|
||||
await this.save()
|
||||
|
||||
// TODO other things?
|
||||
await this.syncTelegramUsers(telegramPOV, users)
|
||||
|
||||
return this.roomID
|
||||
} catch (err) {
|
||||
@@ -90,8 +102,8 @@ class Portal {
|
||||
updateInfo(telegramPOV, dialog) {
|
||||
let changed = false
|
||||
if (this.peer.type === "channel") {
|
||||
if (telegramPOV && this.accessHashes.get(telegramPOV.userID) !== +dialog.access_hash) {
|
||||
this.accessHashes.set(telegramPOV.userID, +dialog.access_hash)
|
||||
if (telegramPOV && this.accessHashes.get(telegramPOV.userID) !== dialog.access_hash) {
|
||||
this.accessHashes.set(telegramPOV.userID, dialog.access_hash)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
|
||||
+31
-14
@@ -18,7 +18,7 @@ class TelegramPeer {
|
||||
constructor(type, id, accessHash) {
|
||||
this.type = type
|
||||
this.id = id
|
||||
this.accessHash = +(accessHash || 0)
|
||||
this.accessHash = accessHash
|
||||
this.username = undefined
|
||||
this.title = undefined
|
||||
}
|
||||
@@ -28,26 +28,37 @@ class TelegramPeer {
|
||||
case "peerChat":
|
||||
return new TelegramPeer("chat", peer.chat_id)
|
||||
case "peerUser":
|
||||
return new TelegramPeer("user", peer.user_id, peer.access_hash || 0)
|
||||
return new TelegramPeer("user", peer.user_id, peer.access_hash)
|
||||
case "peerChannel":
|
||||
return new TelegramPeer("channel", peer.channel_id, peer.access_hash || 0)
|
||||
return new TelegramPeer("channel", peer.channel_id, peer.access_hash)
|
||||
default:
|
||||
throw new Error(`Unrecognized peer type ${peer._}`)
|
||||
}
|
||||
}
|
||||
|
||||
async getAccessHash(app, telegramPOV) {
|
||||
if (this.type === "chat" || this.accessHash > 0) {
|
||||
/**
|
||||
* Load the access hash for a specific puppeted Telegram user from the channel portal or TelegramUser info.
|
||||
*
|
||||
* @param {MautrixTelegram} app The instance of {@link MautrixTelegram} to use.
|
||||
* @param {TelegramPuppet} telegramPOV The puppeted Telegram user for whom the access hash is needed.
|
||||
* @param {Portal} [portal] Optional channel {@link Portal} instance to avoid calling {@link app#getPortalByPeer(peer)}.
|
||||
* Only used if {@link #type} is {@linkplain user}.
|
||||
* @param {TelegramUser} [user] Optional {@link TelegramUser} instance to avoid calling {@link app#getTelegramUser(id)}.
|
||||
* Only used if {@link #type} is {@linkplain channel}.
|
||||
* @returns {Promise<boolean>} Whether or not the access hash was found and loaded.
|
||||
*/
|
||||
async loadAccessHash(app, telegramPOV, { portal, user }) {
|
||||
if (this.type === "chat") {
|
||||
return true
|
||||
} else if (this.type === "user") {
|
||||
const user = await app.getTelegramUser(this.id)
|
||||
user = user || await app.getTelegramUser(this.id)
|
||||
if (user.accessHashes.has(telegramPOV.userID)) {
|
||||
this.accessHash = user.accessHashes.get(telegramPOV.userID)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} else if (this.type === "channel") {
|
||||
const portal = await app.getPortalByPeer(this)
|
||||
portal = portal || await app.getPortalByPeer(this)
|
||||
if (portal.accessHashes.has(telegramPOV.userID)) {
|
||||
this.accessHash = portal.accessHashes.get(telegramPOV.userID)
|
||||
return true
|
||||
@@ -56,7 +67,7 @@ class TelegramPeer {
|
||||
}
|
||||
}
|
||||
|
||||
updateInfo(dialog) {
|
||||
async updateInfo(dialog) {
|
||||
let changed = false
|
||||
if (this.type === "channel") {
|
||||
if (this.username !== dialog.username) {
|
||||
@@ -68,11 +79,14 @@ class TelegramPeer {
|
||||
this.title = dialog.title
|
||||
changed = true
|
||||
}
|
||||
if (changed) {
|
||||
this.save()
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
async getInfo(telegramPOV) {
|
||||
let info, participants
|
||||
let info, users
|
||||
switch(this.type) {
|
||||
case "user":
|
||||
throw new Error("Can't get chat info of user")
|
||||
@@ -80,24 +94,27 @@ class TelegramPeer {
|
||||
info = await telegramPOV.client("messages.getFullChat", {
|
||||
chat_id: this.id,
|
||||
})
|
||||
participants = info.users
|
||||
users = info.users
|
||||
break
|
||||
case "channel":
|
||||
// FIXME I'm broken (Error: CHANNEL_INVALID)
|
||||
info = await telegramPOV.client("channels.getFullChannel", {
|
||||
channel: this.toInputChannel(),
|
||||
})
|
||||
participants = await telegramPOV.client("channels.getParticipants", {
|
||||
const participants = await telegramPOV.client("channels.getParticipants", {
|
||||
channel: this.toInputChannel(),
|
||||
filter: { _: "channelParticipantsRecent" },
|
||||
offset: 0,
|
||||
limit: 1000,
|
||||
})
|
||||
break
|
||||
users = participants.users
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unknown peer type ${this.type}`)
|
||||
}
|
||||
return { info, participants }
|
||||
return {
|
||||
info: info.chats[0],
|
||||
users
|
||||
}
|
||||
}
|
||||
|
||||
toInputPeer() {
|
||||
|
||||
@@ -18,6 +18,21 @@ const os = require("os")
|
||||
const telegram = require("telegram-mtproto")
|
||||
const TelegramPeer = require("./telegram-peer")
|
||||
|
||||
const META_FROM_FILETYPE = {
|
||||
"storage.fileGif": {
|
||||
mimetype: "image/gif",
|
||||
extension: "gif",
|
||||
},
|
||||
"storage.fileJpeg": {
|
||||
mimetype: "image/jpeg",
|
||||
extension: "jpeg",
|
||||
},
|
||||
"storage.filePng": {
|
||||
mimetype: "image/png",
|
||||
extension: "png",
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* TelegramPuppet represents a Telegram account being controlled from Matrix.
|
||||
*/
|
||||
@@ -306,6 +321,22 @@ class TelegramPuppet {
|
||||
}
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
async getFile(location) {
|
||||
location = Object.assign({}, location, {_: "inputFileLocation"})
|
||||
delete location.dc_id
|
||||
const file = await this.client("upload.getFile", {
|
||||
location,
|
||||
offset: 0,
|
||||
limit: 100*1024*1024,
|
||||
})
|
||||
const meta = META_FROM_FILETYPE[file.type._]
|
||||
if (meta) {
|
||||
file.mimetype = meta.mimetype
|
||||
file.extension = meta.extension
|
||||
}
|
||||
return file
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TelegramPuppet
|
||||
|
||||
+26
-11
@@ -67,12 +67,8 @@ class TelegramUser {
|
||||
}
|
||||
}
|
||||
|
||||
updateInfo(telegramPOV, user) {
|
||||
async updateInfo(telegramPOV, user) {
|
||||
let changed = false
|
||||
if (telegramPOV && this.accessHashes.get(telegramPOV.userID) !== +user.access_hash) {
|
||||
this.accessHashes.set(telegramPOV.userID, +user.access_hash)
|
||||
changed = true
|
||||
}
|
||||
if (this.firstName !== user.first_name) {
|
||||
this.firstName = user.first_name
|
||||
changed = true
|
||||
@@ -85,12 +81,31 @@ class TelegramUser {
|
||||
this.username = user.username
|
||||
changed = true
|
||||
}
|
||||
if (await this.updateAvatarImageFrom(telegramPOV, user)) {
|
||||
changed = true
|
||||
}
|
||||
if (telegramPOV && this.accessHashes.get(telegramPOV.userID) !== user.access_hash) {
|
||||
this.accessHashes.set(telegramPOV.userID, user.access_hash)
|
||||
changed = true
|
||||
}
|
||||
|
||||
const userInfo = await this.intent.getProfileInfo(this.mxid, "displayname")
|
||||
if (userInfo.displayname !== this.getDisplayName()) {
|
||||
console.log(userInfo.displayname)
|
||||
this.intent.setDisplayName(
|
||||
this.app.config.bridge.displayname_template.replace("${DISPLAYNAME}", this.getDisplayName()))
|
||||
console.log((await this.intent.getProfileInfo(this.mxid, "displayname")).displayname)
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
this.save()
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
get intent() {
|
||||
if (!this._intent) {
|
||||
this._intent = this.app.getIntentForTelegramID(this.id)
|
||||
this._intent = this.app.getIntentForTelegramUser(this.id)
|
||||
}
|
||||
return this._intent
|
||||
}
|
||||
@@ -145,7 +160,7 @@ class TelegramUser {
|
||||
|
||||
async updateAvatarImageFrom(telegramPOV, user) {
|
||||
if (!user.photo) {
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
const photo = user.photo.photo_big
|
||||
@@ -153,7 +168,7 @@ class TelegramUser {
|
||||
this.photo.dc_id === photo.dc_id &&
|
||||
this.photo.volume_id === photo.volume_id &&
|
||||
this.photo.local_id === photo.local_id) {
|
||||
return this.avatarURL
|
||||
return false
|
||||
}
|
||||
|
||||
const file = await telegramPOV.getFile(photo)
|
||||
@@ -165,15 +180,15 @@ class TelegramUser {
|
||||
type: file.mimetype,
|
||||
})
|
||||
|
||||
this.avatarURL = response.content_uri
|
||||
this.avatarURL = uploaded.content_uri
|
||||
this.photo = {
|
||||
dc_id: photo.dc_id,
|
||||
volume_id: photo.volume_id,
|
||||
local_id: photo.local_id,
|
||||
}
|
||||
|
||||
await this.app.putUser(this)
|
||||
return this.avatarURL
|
||||
await this.intent.setAvatarUrl(this.avatarURL)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user