🔧 Изменение(bot-commands): Изменил передаваемый аргумент для saveResume на объект.ResumeListItem.

This commit is contained in:
Oscar
2026-05-27 13:40:25 +03:00
parent 9ee0ebe2d2
commit 9acdf2778c
5 changed files with 56 additions and 18 deletions

View File

@@ -7,7 +7,7 @@
"build": "tsc", "build": "tsc",
"start": "node --env-file=.env dist/index.js", "start": "node --env-file=.env dist/index.js",
"db-view": "yarn prisma studio", "db-view": "yarn prisma studio",
"db-migrate": "npx prisma migrate dev --name init npx prisma generate ", "db-migrate": "npx prisma migrate dev",
"db-deploy": "npx prisma migrate deploy", "db-deploy": "npx prisma migrate deploy",
"db-migrate-server": "git pull npx prisma migrate deploy", "db-migrate-server": "git pull npx prisma migrate deploy",
"lint": "eslint .", "lint": "eslint .",

View File

@@ -0,0 +1,15 @@
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_Resume" (
"id" TEXT NOT NULL PRIMARY KEY,
"data" TEXT NOT NULL,
"title" TEXT NOT NULL DEFAULT '',
"telegramId" BIGINT NOT NULL,
CONSTRAINT "Resume_telegramId_fkey" FOREIGN KEY ("telegramId") REFERENCES "User" ("telegramId") ON DELETE CASCADE ON UPDATE CASCADE
);
INSERT INTO "new_Resume" ("data", "id", "telegramId") SELECT "data", "id", "telegramId" FROM "Resume";
DROP TABLE "Resume";
ALTER TABLE "new_Resume" RENAME TO "Resume";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;

View File

@@ -31,6 +31,7 @@ model Resume {
id String @id id String @id
user User @relation(references: [telegramId], fields: [telegramId], onDelete: Cascade) user User @relation(references: [telegramId], fields: [telegramId], onDelete: Cascade)
data String data String
title String @default("")
telegramId BigInt telegramId BigInt
} }

View File

@@ -109,7 +109,7 @@ async function doLogin(chatId: number, email: string): Promise<void> {
await bot.sendMessage(chatId, '⚠️ Резюме не найдены. Создайте резюме на hh.ru') await bot.sendMessage(chatId, '⚠️ Резюме не найдены. Создайте резюме на hh.ru')
} }
else if (resumes.length === 1) { else if (resumes.length === 1) {
await saveResume(chatId, resumes[0].href) await saveResume(chatId, resumes[0])
await bot.sendMessage(chatId, `✅ Резюме сохранено: ${resumes[0].title}`) await bot.sendMessage(chatId, `✅ Резюме сохранено: ${resumes[0].title}`)
} }
else { else {
@@ -234,7 +234,7 @@ export function registerHHCommands() {
await showResult(chatId, messageId, '📋 Резюме не найдено.\n\nВыбери резюме через кнопку 📄 Выбрать резюме.') await showResult(chatId, messageId, '📋 Резюме не найдено.\n\nВыбери резюме через кнопку 📄 Выбрать резюме.')
break break
} }
const MAX = 3800 const MAX = 10000
const text = resume.data.length > MAX const text = resume.data.length > MAX
? `${resume.data.slice(0, MAX)}\n\n… (текст обрезан)` ? `${resume.data.slice(0, MAX)}\n\n… (текст обрезан)`
: resume.data : resume.data
@@ -341,7 +341,7 @@ export function registerHHCommands() {
message_id: messageId, message_id: messageId,
reply_markup: { inline_keyboard: [] }, reply_markup: { inline_keyboard: [] },
}) })
await saveResume(chatId, resumes[0].href) await saveResume(chatId, resumes[0])
await showResult(chatId, messageId, `✅ Резюме сохранено: ${resumes[0].title}`) await showResult(chatId, messageId, `✅ Резюме сохранено: ${resumes[0].title}`)
} }
else { else {
@@ -364,7 +364,7 @@ export function registerHHCommands() {
message_id: messageId, message_id: messageId,
reply_markup: { inline_keyboard: [] }, reply_markup: { inline_keyboard: [] },
}) })
await saveResume(chatId, resume.href) await saveResume(chatId, resume)
state.pendingResumes = [] state.pendingResumes = []
await showResult(chatId, messageId, `✅ Резюме выбрано: ${resume.title}`) await showResult(chatId, messageId, `✅ Резюме выбрано: ${resume.title}`)
} }

View File

@@ -81,6 +81,9 @@ export async function checkIsAuth(telegramId: bigint | number) {
catch { catch {
return null return null
} }
finally {
await browser.close()
}
} }
export async function listResumes(chatId: number): Promise<ResumeListItem[]> { export async function listResumes(chatId: number): Promise<ResumeListItem[]> {
@@ -96,12 +99,18 @@ export async function listResumes(chatId: number): Promise<ResumeListItem[]> {
await page.waitForSelector('[data-qa^="resume-card-link-"]', { timeout: 10000 }) await page.waitForSelector('[data-qa^="resume-card-link-"]', { timeout: 10000 })
const resumes = await page.$$eval( const resumes = await page.$$eval(
'[data-qa^="resume-card-link-"]', '[data-qa^="resume-card-link-"]',
links => links.map(a => ({ links => links.map((a) => {
const card = a.closest('[data-qa^="resume-card"]') ?? a.parentElement
const titleEl = card?.querySelector('[data-qa="cell-text-content"]')
return {
href: (a as HTMLAnchorElement).getAttribute('href') ?? '', href: (a as HTMLAnchorElement).getAttribute('href') ?? '',
title: a.textContent?.trim() ?? '(без названия)', title: titleEl?.textContent?.trim() ?? '(без названия)',
})), }
}),
) )
await browser.close() await browser.close()
console.log(resumes)
return resumes return resumes
} }
catch (e) { catch (e) {
@@ -115,12 +124,15 @@ export async function listResumes(chatId: number): Promise<ResumeListItem[]> {
throw lastError! throw lastError!
} }
export async function saveResume(chatId: number, resumeHref: string): Promise<string | undefined> { export async function saveResume(chatId: number, resumeItem: ResumeListItem): Promise<string | undefined> {
const browser = await getBrowser() const browser = await getBrowser()
const context = await browser.newContext() const context = await browser.newContext()
const page = await context.newPage() const page = await context.newPage()
await loadSession(page, chatId) await loadSession(page, chatId)
const resumeHref = resumeItem.href
const title = resumeItem.title
const id = new URL(`https://hh.ru${resumeHref}`).pathname.split('/').pop()! const id = new URL(`https://hh.ru${resumeHref}`).pathname.split('/').pop()!
const resumeUrl = `https://hh.ru/resume_converter/resume.txt?hash=${id}&type=txt&hhtmFrom=&hhtmSource=resume` const resumeUrl = `https://hh.ru/resume_converter/resume.txt?hash=${id}&type=txt&hhtmFrom=&hhtmSource=resume`
@@ -131,8 +143,8 @@ export async function saveResume(chatId: number, resumeHref: string): Promise<st
resume = await page.locator('.resume').innerText() resume = await page.locator('.resume').innerText()
await prisma.resume.upsert({ await prisma.resume.upsert({
where: { id }, where: { id },
create: { data: resume, id, telegramId: chatId }, create: { data: resume, id, telegramId: chatId, title },
update: { data: resume }, update: { data: resume, title },
}) })
} }
catch (e) { catch (e) {
@@ -206,8 +218,7 @@ export async function applyToJobs(
await status(`✍️ Генерирую письмо: ${vacancy.title}`) await status(`✍️ Генерирую письмо: ${vacancy.title}`)
const letter = await createMessage(resume.data, description, user!.prompt) const letterPromise = createMessage(resume.data, description, user!.prompt)
await keep(`✅ <b>${vacancy.title}</b>\n\n${letter}`)
const applyBtn = await page.$('[data-qa="vacancy-response-link-top"]') const applyBtn = await page.$('[data-qa="vacancy-response-link-top"]')
if (!applyBtn) { if (!applyBtn) {
@@ -220,19 +231,30 @@ export async function applyToJobs(
await applyBtn.click() await applyBtn.click()
await page.waitForTimeout(randomDelay()) await page.waitForTimeout(randomDelay())
// Выбор реюзме // Выбор резюме
const currentResume = await page.$('[data-qa="resume-title"]') const currentResumeEl = await page.$('[data-qa="resume-title"]')
console.log(currentResume?.textContent()) const currentResumeTitle = (await currentResumeEl?.innerText())?.trim() ?? ''
console.log('Текущее резюме на странице:', currentResumeTitle)
console.log('Ожидаемое резюме из БД:', resume.title)
if (currentResumeTitle !== resume.title) {
// TODO: добавить логику смены резюме
console.log('Резюме не совпадает, нужно сменить')
currentResumeEl?.focus()
currentResumeEl?.click()
}
await page.pause() await page.pause()
const addLetter = await page.$('[data-qa="add-cover-letter"]') const addLetter = await page.$('[data-qa="add-cover-letter"]')
if (addLetter) { if (addLetter) {
await page.pause()
await addLetter?.hover() await addLetter?.hover()
await addLetter?.click() await addLetter?.click()
} }
await keep(`✅ <b>${vacancy.title}</b>\n\n${letter}`)
const letter = await letterPromise
if (letter) { if (letter) {
const letterInput = await page.$('[data-qa="vacancy-response-popup-form-letter-input"]') const letterInput = await page.$('[data-qa="vacancy-response-popup-form-letter-input"]')