Skip to content
Snippets Groups Projects
telegram.service.ts 7.11 KiB
Newer Older
  • Learn to ignore specific revisions
  • Pascal Kosak's avatar
    Pascal Kosak committed
    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';
    
    @Injectable()
    export class TelegramService {
    
    Pascal Kosak's avatar
    Pascal Kosak committed
        private telegram: TelegramBot;
    
        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(/^\/commit (.+)/, this.commit.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 start(msg: Message, match: RegExpMatchArray) {
            await this.telegram.sendMessage(
                msg.chat.id,
                `/register [Name]\n/state\n/unregister`,
            );
        }
    
        async commit(msg: Message, match: RegExpMatchArray) {
            if (!match[1])
                return void (await this.telegram.sendMessage(
                    msg.chat.id,
                    'No message',
                ));
    
            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.create({
                data: {
                    agentId: agent.id,
                    content: match[1],
                },
            });
    
            await this.telegram.sendMessage(msg.chat.id, 'Commit accepted');
        }
    
        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.unlockEntry.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 entries = await this.prismaService.entry.count({
                where: { agentId: agent.id },
            });
    
            const unlockEntries = await this.prismaService.unlockEntry.count({
                where: { agentId: agent.id },
            });
    
            await this.telegram.sendMessage(
                msg.chat.id,
                `Id: ${agent.id}\nName: ${agent.name}\nCode: ${agent.slug}\nPublic Entries: ${entries}\nUnlockable Entries: ${unlockEntries}`,
            );
        }
    
        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) },
            });
    
            if (metadata.type === 'photo') {
                let file,
                    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(), 'static', 'photos', `${id}.jpg`),
                );
                const pipe = this.telegram.getFileStream(file).pipe(dest);
    
                await new Promise((resolve) => pipe.on('finish', resolve));
    
                await this.prismaService.unlockEntry.create({
                    data: {
                        type: 'picture',
                        agentId: agent.id,
                        path: `${id}.jpg`,
                    },
                });
    
                return void (await this.telegram.sendMessage(
                    msg.chat.id,
                    `Accepted Photo`,
                ));
            } else if (metadata.type === 'text') {
                await this.prismaService.unlockEntry.create({
                    data: {
                        type: 'text',
                        agentId: agent.id,
                        content: msg.text,
                    },
                });
    
                return void (await this.telegram.sendMessage(
                    msg.chat.id,
                    'Accepted Text',
                ));
            } else if (metadata.type === 'location') {
                await this.prismaService.unlockEntry.create({
                    data: {
                        agentId: agent.id,
                        type: 'location',
                        lat: msg.location.latitude.toString(),
                        lon: msg.location.longitude.toString(),
                    },
                });
    
                return void (await this.telegram.sendMessage(
                    msg.chat.id,
                    'Accepted Location',
                ));
            } else {
                return void (await this.telegram.sendMessage(
                    msg.chat.id,
                    'Unsupported DataType',
                ));
    
    Pascal Kosak's avatar
    Pascal Kosak committed
            }
        }
    
    Pascal Kosak's avatar
    Pascal Kosak committed
    
        private async isRegistered(uid: string | number): Promise<boolean> {
            return (
                (await this.prismaService.agent.count({
                    where: { uid: String(uid) },
                })) > 0
            );
        }
    
    Pascal Kosak's avatar
    Pascal Kosak committed
    }