Newer
Older
import { Injectable } from '@nestjs/common';
import { Message, Metadata } from 'node-telegram-bot-api';
import * as TelegramBot from 'node-telegram-bot-api';
import { PrismaService } from '../prisma/prisma.service';
import * as fs from 'fs';
import * as path from 'path';
import { v4 as uuid } from 'uuid';
import { Entry } from '@prisma/client';
private messageCache = new Map<number, Partial<Entry>>();
constructor(private prismaService: PrismaService) {
this.telegram = new TelegramBot(process.env.BOT_TOKEN, {
polling: true,
});
this.telegram.onText(/^\/register (.+)/, this.register.bind(this));
this.telegram.onText(/^\/unregister/, this.unregister.bind(this));
this.telegram.onText(/^\/state/, this.state.bind(this));
this.telegram.onText(/^\/start/, this.start.bind(this));
this.telegram.onText(/^\/private/, this.private.bind(this));
this.telegram.onText(/^\/public/, this.public.bind(this));
this.telegram.onText(/^\/clear/, this.clear.bind(this));
this.telegram.on('message', this.supplyValue.bind(this));
}
private lower = parseInt('aaaaaaa', 36);
private upper = parseInt('zzzzzzzz', 36);
private generateSlug() {
return Math.floor(
Math.random() * (this.upper - this.lower) + this.lower,
).toString(36);
}
async private(msg: Message, match: RegExpMatchArray) {
this.commitMessage(msg.from.id, true, msg);
}
async public(msg: Message, match: RegExpMatchArray) {
this.commitMessage(msg.from.id, false, msg);
}
async clear(msg: Message, match: RegExpMatchArray) {
this.messageCache.delete(msg.from.id);
return void (await this.telegram.sendMessage(
'Message Queue cleared!',
));
async commitMessage(id: number, isPrivate: boolean, msg: Message) {
if (!(await this.isRegistered(msg.from.id)))
return void (await this.telegram.sendMessage(
msg.chat.id,
'Not registered!',
if (!this.messageCache.has(id))
return void (await this.telegram.sendMessage(
msg.chat.id,
'No queued Messages!',
const entry = this.messageCache.get(msg.from.id);
entry.private = isPrivate;
this.messageCache.delete(msg.from.id);
data: entry as any,
// TODO: Send a notification to subscriptions
}
async start(msg: Message, match: RegExpMatchArray) {
await this.telegram.sendMessage(
msg.chat.id,
`/register [Name]\n/state\n/unregister`,
);
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
}
async register(msg: Message, match: RegExpMatchArray) {
if (!match[1])
return void (await this.telegram.sendMessage(
msg.chat.id,
'Invalid name format',
));
if (await this.isRegistered(msg.from.id))
return void (await this.telegram.sendMessage(
msg.chat.id,
'Already registered',
));
const agent = await this.prismaService.agent.create({
data: {
uid: String(msg.from.id),
name: match[1],
slug: this.generateSlug(),
},
});
await this.telegram.sendMessage(
msg.chat.id,
`Id: ${agent.id}\nName: ${agent.name}\nCode: ${agent.slug}`,
);
}
async unregister(msg: Message, match: RegExpMatchArray) {
if (!(await this.isRegistered(msg.from.id)))
return void (await this.telegram.sendMessage(
msg.chat.id,
'Not registered!',
));
const agent = await this.prismaService.agent.findFirst({
where: { uid: String(msg.from.id) },
});
await this.prismaService.entry.deleteMany({
where: { agentId: agent.id },
});
await this.prismaService.entry.deleteMany({
where: { agentId: agent.id },
});
await this.prismaService.agent.delete({
where: { id: agent.id },
});
await this.telegram.sendMessage(
msg.chat.id,
'Successfully deleted all Entries',
);
}
async state(msg: Message, match: RegExpMatchArray) {
if (!(await this.isRegistered(msg.from.id)))
return void (await this.telegram.sendMessage(
msg.chat.id,
'Not registered!',
));
const agent = await this.prismaService.agent.findFirst({
where: { uid: String(msg.from.id) },
});
const publicEntries = await this.prismaService.entry.count({
where: { agentId: agent.id, private: false },
const privateEntries = await this.prismaService.entry.count({
where: { agentId: agent.id, private: true },
});
await this.telegram.sendMessage(
msg.chat.id,
`Id: ${agent.id}\nName: ${agent.name}\nCode: ${agent.slug}\nPublic Entries: ${publicEntries}\nPrivate Entries: ${privateEntries}`,
async receiveImage(msg: Message): Promise<Partial<Entry>> {
let file;
let size = -1;
for (const p of msg.photo) {
if (p.width > size) {
size = p.width;
file = p.file_id;
}
}
const id = uuid();
const dest = fs.createWriteStream(
path.join(process.cwd(), 'photos', `${id}.jpg`),
);
const pipe = this.telegram.getFileStream(file).pipe(dest);
await new Promise((resolve) => pipe.on('finish', resolve));
return {
image: `${id}.jpg`,
};
}
async supplyValue(msg: Message, metadata: Metadata) {
if (metadata.type === 'text' && msg.text.startsWith('/')) return;
if (!(await this.isRegistered(msg.from.id))) return;
const agent = await this.prismaService.agent.findFirst({
where: { uid: String(msg.from.id) },
});
let entry: Partial<Entry> = {};
if (this.messageCache.has(msg.from.id))
entry = this.messageCache.get(msg.from.id);
entry.agentId = agent.id;
if (metadata.type === 'photo') {
const imageEntry = await this.receiveImage(msg);
if (entry.image)
await this.telegram.sendMessage(
msg.chat.id,
'Overwriting previous image',
);
entry.image = imageEntry.image;
await this.telegram.sendMessage(
'Queued Image',
);
entry.content = msg.text;
await this.telegram.sendMessage(
'Queued Text',
);
entry.lat = msg.location.latitude.toString();
entry.lon = msg.location.longitude.toString();
await this.telegram.sendMessage(
'Queued Location',
);
} else {
return void (await this.telegram.sendMessage(
msg.chat.id,
'Unsupported DataType',
));
this.messageCache.set(msg.from.id, entry);
private async isRegistered(uid: string | number): Promise<boolean> {
return (
(await this.prismaService.agent.count({
where: { uid: String(uid) },
})) > 0
);
}