add basic functionality for frontend, json db

This commit is contained in:
2024-05-25 15:05:18 +02:00
parent d2763be27b
commit 7d55082f4d
44 changed files with 4146 additions and 22 deletions

View File

@@ -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
View 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 };

View File

@@ -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);

View 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;
}

View File

@@ -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 });

View File

@@ -6,4 +6,7 @@ export type UserData = {
chatId: string;
};
export type Data = Record<string, UserData>;
export type Data = {
rawData: Record<string, UserData>;
groups: UserData[][];
};