Skip to content
Snippets Groups Projects
telegram.service.ts 7.11 KiB
Newer Older
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
}