mirror of
https://github.com/ershisan99/flashcards-admin-bot.git
synced 2025-12-17 20:59:26 +00:00
add basic functionality for frontend, json db
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { Stage, WizardScene } from 'telegraf/scenes';
|
||||
import { Data, UserData } from '../types.js';
|
||||
import fs from 'fs';
|
||||
import { UserData } from '../types.js';
|
||||
import * as db from '../db.js';
|
||||
|
||||
const superWizard = new WizardScene<any>(
|
||||
'add_to_team_wizard',
|
||||
@@ -135,9 +135,10 @@ const superWizard = new WizardScene<any>(
|
||||
...data,
|
||||
tgUsername: ctx.from?.username,
|
||||
chatId,
|
||||
userId: userId?.toString() ?? '',
|
||||
};
|
||||
|
||||
updateData({ userId: userId?.toString() ?? '', ...dataWithTgUsername });
|
||||
await updateData(dataWithTgUsername);
|
||||
await ctx.reply(
|
||||
`Спасибо за регистрацию! Мы свяжемся с тобой в ближайшее время.`,
|
||||
);
|
||||
@@ -152,10 +153,8 @@ const superWizard = new WizardScene<any>(
|
||||
|
||||
export const stage = new Stage([superWizard]);
|
||||
|
||||
function updateData({ ...rest }: UserData) {
|
||||
const data = fs.readFileSync('./data.json', 'utf8');
|
||||
const dataObj = JSON.parse(data) as Data;
|
||||
dataObj[rest.userId] = rest;
|
||||
const newDataStr = JSON.stringify(dataObj);
|
||||
fs.writeFileSync('./data.json', newDataStr, 'utf8');
|
||||
async function updateData({ ...rest }: UserData) {
|
||||
const data = await db.readData();
|
||||
data.rawData[rest.userId] = rest;
|
||||
await db.writeData(data);
|
||||
}
|
||||
|
||||
55
src/db.ts
Normal file
55
src/db.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { promises as fsp } from 'node:fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import path from 'node:path';
|
||||
|
||||
export type UserData = {
|
||||
name: string;
|
||||
availableTime: { from: number; to: number | null };
|
||||
tgUsername: string;
|
||||
userId: string;
|
||||
chatId: string;
|
||||
};
|
||||
|
||||
export type Data = {
|
||||
rawData: Record<string, UserData>;
|
||||
groups: UserData[][];
|
||||
};
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const rootDir = path.join(__dirname, '../..');
|
||||
const dataDir = path.join(rootDir, 'data');
|
||||
const dataFilePath = path.join(dataDir, 'data.json');
|
||||
|
||||
const initialData: Data = {
|
||||
rawData: {},
|
||||
groups: [],
|
||||
};
|
||||
|
||||
async function readData(): Promise<Data> {
|
||||
try {
|
||||
const data = await fsp.readFile(dataFilePath, 'utf-8');
|
||||
return JSON.parse(data);
|
||||
} catch (error) {
|
||||
if (error.code === 'ENOENT') {
|
||||
try {
|
||||
await writeData(initialData);
|
||||
return initialData;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function writeData(data: Data): Promise<void> {
|
||||
try {
|
||||
const jsonData = JSON.stringify(data, null, 2);
|
||||
await fsp.writeFile(dataFilePath, jsonData, 'utf-8');
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export { readData, writeData, initialData };
|
||||
@@ -6,7 +6,7 @@ generateGroups();
|
||||
function generateGroups() {
|
||||
const data = fs.readFileSync('./data.json', 'utf8');
|
||||
const dataObj = JSON.parse(data) as Data;
|
||||
const groupedUsers = groupByTime(dataObj);
|
||||
const groupedUsers = groupByTime(dataObj.rawData);
|
||||
fs.writeFileSync('./groups.json', JSON.stringify(groupedUsers), 'utf8');
|
||||
generateJsFile(groupedUsers);
|
||||
}
|
||||
@@ -18,6 +18,7 @@ function generateJsFile(users: UserData[][]) {
|
||||
|
||||
fs.writeFileSync('./index.js', jsFile, 'utf8');
|
||||
}
|
||||
|
||||
function groupByTime(users: Record<string, UserData>): UserData[][] {
|
||||
const allUsers = Object.values(users);
|
||||
|
||||
|
||||
28
src/handlers/group-users.ts
Normal file
28
src/handlers/group-users.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { UserData } from '../types.js';
|
||||
|
||||
export function groupByTime(users: Record<string, UserData>): UserData[][] {
|
||||
const allUsers = Object.values(users);
|
||||
|
||||
// First, sort all users by their available time from low to high
|
||||
allUsers.sort((a, b) => a.availableTime.from - b.availableTime.from);
|
||||
|
||||
const groups: UserData[][] = [];
|
||||
let currentGroup: UserData[] = [];
|
||||
|
||||
allUsers.forEach((user) => {
|
||||
currentGroup.push(user);
|
||||
|
||||
// If the current group reaches 3 members, start a new group
|
||||
if (currentGroup.length === 3) {
|
||||
groups.push(currentGroup);
|
||||
currentGroup = []; // Reset for next group
|
||||
}
|
||||
});
|
||||
|
||||
// Add the last group if it has less than 3 members and is not empty
|
||||
if (currentGroup.length > 0) {
|
||||
groups.push(currentGroup);
|
||||
}
|
||||
|
||||
return groups;
|
||||
}
|
||||
@@ -1,34 +1,87 @@
|
||||
// Import the framework and instantiate it
|
||||
import Fastify from 'fastify';
|
||||
import fs from 'fs';
|
||||
import { dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import path from 'node:path';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
import * as db from './db.js';
|
||||
import { promises as fsp } from 'node:fs';
|
||||
import { groupByTime } from './handlers/group-users.js';
|
||||
import dotenv from 'dotenv';
|
||||
import { session, Telegraf } from 'telegraf';
|
||||
import { stage } from './bot/setup-wizard-stage.js';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const rootDir = path.join(__dirname, '../..');
|
||||
const dataDir = path.join(rootDir, 'data');
|
||||
const dataFilePath = path.join(dataDir, 'data.json');
|
||||
const preregisteredFilePath = path.join(dataDir, 'preregistered.json');
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const BOT_TOKEN = process.env.BOT_TOKEN;
|
||||
|
||||
if (!BOT_TOKEN) {
|
||||
throw new Error('BOT_TOKEN is required!');
|
||||
}
|
||||
|
||||
const bot = new Telegraf(BOT_TOKEN);
|
||||
bot.use(session());
|
||||
bot.use(stage.middleware());
|
||||
bot.command('add_to_team', (ctx) => {
|
||||
// @ts-expect-error wtf
|
||||
ctx.scene.enter('add_to_team_wizard');
|
||||
});
|
||||
|
||||
const fastify = Fastify({
|
||||
logger: true,
|
||||
});
|
||||
|
||||
// Declare a route
|
||||
fastify.get('/', async function handler(request, reply) {
|
||||
return { hello: 'world' };
|
||||
return await db.readData();
|
||||
});
|
||||
|
||||
// Declare a route
|
||||
fastify.get('/prepare-db', async function handler(request, reply) {
|
||||
try {
|
||||
fs.writeFileSync(path.join(dataDir, 'data.json'), '{}', 'utf8');
|
||||
return reply.code(200).send('ok');
|
||||
await db.writeData(db.initialData);
|
||||
return reply.code(200).send();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return reply.code(500).send(err);
|
||||
}
|
||||
});
|
||||
|
||||
fastify.get('/generate-groups', async function handler(request, reply) {
|
||||
try {
|
||||
const data = await db.readData();
|
||||
data.groups = groupByTime(data.rawData);
|
||||
await db.writeData(data);
|
||||
return reply.code(200).send();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return reply.code(500).send(err);
|
||||
}
|
||||
});
|
||||
|
||||
fastify.get('/fill-preregistered', async function handler(request, reply) {
|
||||
try {
|
||||
const preregisteredData = await fsp.readFile(
|
||||
preregisteredFilePath,
|
||||
'utf-8',
|
||||
);
|
||||
const parsedPreregisteredData = JSON.parse(preregisteredData);
|
||||
await db.writeData(parsedPreregisteredData);
|
||||
return reply.code(200).send();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return reply.code(500).send(err);
|
||||
}
|
||||
});
|
||||
|
||||
void bot.launch();
|
||||
|
||||
process.once('SIGINT', () => bot.stop('SIGINT'));
|
||||
process.once('SIGTERM', () => bot.stop('SIGTERM'));
|
||||
|
||||
// Run the server!
|
||||
try {
|
||||
await fastify.listen({ port: 3000 });
|
||||
|
||||
@@ -6,4 +6,7 @@ export type UserData = {
|
||||
chatId: string;
|
||||
};
|
||||
|
||||
export type Data = Record<string, UserData>;
|
||||
export type Data = {
|
||||
rawData: Record<string, UserData>;
|
||||
groups: UserData[][];
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user