qelphybox / hakeshonassybot Goto Github PK
View Code? Open in Web Editor NEWFun telegram bot
License: MIT License
Fun telegram bot
License: MIT License
Kirill Bobykin, [15.05.20 20:10]
завел бота
Kirill Bobykin, [15.05.20 20:10]
/stats
Hake Shonassy, [15.05.20 20:10]
Сообщений за последние 24 часа: @kirillbobykin (1)
Сообщений за последний час: @kirillbobykin (1)
@kirillbobykin - безработный
Он определил, что я безработный, хотя у меня одно сообщение в пятницу 20:10 мск (17:10 UTC). Я думаю стоит определять не по utc, а по мск все таки, сбивает с толку ребят.
Идея ачивки - человек с наибольшим количеством реакций, обозначающих смех. В реакции могут входить:
В пункте 1 следует учесть возможные опечатки, раскладку (f[f[f[f), регистр, производные формы (хех, хихи)
Почему-то нет индексов на продакшн базе
https://cloud.mongodb.com/v2/5ebec54548522155c1a82467#metrics/replicaSet/5ebec6149dea806197732bf3/explorer/hakeshonassydb_production/messages/indexes
У нас постоянно какие-то баги после выкатки, в итоге мы всегда выкатываемся в несколько раундов, чтобы это избежать нам нам нужно как можно более верхнеуровневое тестирование.
Приемлемый уровень, имхо, функции которыми мы реагируем на события в телеграме, нужно выделить в модуль и плотно закрыть его тестами.
GET /api/stupid_achievments
- отдает все поддерживаемые глупые ачивки.
{
"status": "ok",
"stupid_achievments": [
{ "title": "Количество сообщений", "name": "messages_count" },
{ "title": "Безработный", "name": "workless_user" },
{ "title": "Поставщик контента", "name": "content_supplier" },
{ "title": "Худший юзер чата", "name": "worst_chat_user" },
{ "title": "Стикерпакер", "name": "stickerpacker" },
{ "title": "Пропавший без вести", "name": "maybe_died" },
{ "title": "Дудь", "name": "dud" },
{ "title": "Философ", "name": "philosopher" }
]
}
{
"status": "forbidden"
}
Line 4 in 265bee1
(stikerpacker) Юзер который использовал самое большое количество стикерпаков, не считаем количество стикеров.
Hake Shonassy, [16.05.20 03:49]
Сообщений за последние 24 часа: @Johnny3_2 (27), @Andrusishin (12), @null (10), @kirillbobykin (8), @null (7), @Fulgrim_94 (5), @null (4), @null (3), @NobodyKnowsa (3), @null (2)
Сообщений за последний час:
@Johnny3_2 - безработный
Нужно изменить алгоритм определения имени
Сейчас вот так:
Сообщений за последние 24 часа: Вадим (21), Dima (19), Евгений Слиж (17), Alexander Malykh (17), Kirill Bobykin (14), M B (14), Alexey Danilov (12), Melnikov Leonid (11), Дмитрий Старов (4), Alexandr Legotin (3)
Сообщений за последний час: Вадим (2), Kirill Bobykin (2), Alexey Danilov (1)
Alexey Danilov - безработный
Alexey Danilov - поставщик контента
Дмитрий Старов - худший юзер чата
Вадим - стикерпакер
Нужно чтобы было вот так:
Сообщений за последние 24 часа: Вадим (21), Dima (19), Евгений Слиж (17), Alexander Malykh (17), Kirill Bobykin (14), M B (14), Alexey Danilov (12), Melnikov Leonid (11), Дмитрий Старов (4), Alexandr Legotin (3)
Сообщений за последний час: Вадим (2), Kirill Bobykin (2), Alexey Danilov (1)
Alexey Danilov - безработный (123 сообщения в рабочее время за неделю)
Alexey Danilov - поставщик контента (3 картинки, 1 видео)
Дмитрий Старов - худший юзер чата (послал 10 голосовых)
Вадим - стикерпакер (юзает 4 стикерпака)
После ачивок должно появиться уточненение по стату
// src/dbClient.js
class DBClient {
//....
}
const dbClient = new DBClient();
Object.freeze(dbClient);
export default dbClient;
Сейчас при выкатке мы вызываем src/migrate.js
Он падает с логом:
> [email protected] migrate /app
> node src/migrate.js
Start migration...
(node:42) DeprecationWarning: current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.
migration failed with error: MongoError: a collection 'hakeshonassydb_production.messages' already exists
at Connection.<anonymous> (/app/node_modules/mongodb/lib/core/connection/pool.js:451:61)
at Connection.emit (events.js:314:20)
at processMessage (/app/node_modules/mongodb/lib/core/connection/connection.js:452:10)
at TLSSocket.<anonymous> (/app/node_modules/mongodb/lib/core/connection/connection.js:621:15)
at TLSSocket.emit (events.js:314:20)
at addChunk (_stream_readable.js:298:12)
at readableAddChunk (_stream_readable.js:273:9)
at TLSSocket.Readable.push (_stream_readable.js:214:10)
at TLSWrap.onStreamRead (internal/stream_base_commons.js:188:23) {
operationTime: Timestamp { _bsontype: 'Timestamp', low_: 8, high_: 1603202328 },
ok: 0,
code: 48,
codeName: 'NamespaceExists',
'$clusterTime': {
clusterTime: Timestamp { _bsontype: 'Timestamp', low_: 8, high_: 1603202328 },
signature: { hash: [Binary], keyId: [Long] }
}
}
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] migrate: `node src/migrate.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] migrate script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /app/.npm/_logs/2020-10-20T13_58_49_265Z-debug.log
Нужно сделать выполнение идемпотентным, то есть если у нас нет коллекции и индексов, создаём их, если есть то не создаём но и не падаем.
Если в чат в котором есть бот пишут /rickroll
бот шлет в чат эту ссылку https://www.youtube.com/watch?v=dQw4w9WgXcQ
Статистика безработный (workless) не определяется, в чате есть переписки на неделе, но нет ачивки при вызове /stats
Kirill Bobykin, [24.05.20 22:43]
/stats
Hake Shonassy, [24.05.20 22:43]
Сообщений за последние 24 часа: Alexey Danilov (12), Вадим (11), Дмитрий Старов (7), Евгений Слиж (6), Kirill Bobykin (5), Alexander Malykh (5), Ivan Slotin (3), M B (2)
Сообщений за последний час: Kirill Bobykin (5), Alexander Malykh (4), Ivan Slotin (2), Евгений Слиж (1)
Сообщений за последние 24 часа: Alexey Danilov (93), Вадим (77), Melnikov Leonid (48), Kirill Bobykin (43), M B (35), Евгений Слиж (34), Alexander Malykh (23), Dima (21), Дмитрий Старов (7), Theodor (6), Ivan Slotin (5), Vlad Malikh (2)
Сообщений за последний час: Alexey Danilov (4), M B (2), Евгений Слиж (1)
Alexey Danilov - безработный (614 сообщения в рабочее время за неделю)
Alexey Danilov - поставщик контента (картинок - 10, видео - 0)
Дмитрий Старов - худший юзер чата (послал 4 голосовых)
Вадим - стикерпакер (юзает 26 стикерпака)
Roma Kuhtin - наверное помер
Сейчас ачивки считаются за последнюю неделю начиная с ближайшего понедельника. Необходимо исправить логику, чтобы считало за последние 7 дней.
Описание ошибки
На данный момент часть ачивок редко активируются и при выводе /stats можно месяцами видеть одного и того же человека под определённой ачивкой.
Предлагаю в вывод /stats показывать только те ачивки, которые активировались в промежутке последних 7 дней.
Сделать выборку за последние 7 дней. Как в безработном только не вычитая выходные и нерабочие часы. То есть если сегодня 26 августва(среда), то собрать надо с 20 августа (прошлый четверг) по сегодня 26е.
Страница логина: https://www.figma.com/file/cJUtYaG9QxcVZB9fFntQtt/Hake-Shonassy?node-id=17%3A210
Страница должна быть доступна только незалогиненым пользователям в корне сайта (путь /
, например http://localhost:3000/
). Залогиненых пользователей должно отправлять на /stupid_achievements
Определить, что юзер залогинен можно по сессии в cookies: в поле hake_session
будет json c полями id, first_name, last_name, username, photo_url, auth_date, hash
. Если поле пусто - юзер не залогинен.
На страницу нужно добавить телеграм логин виджет в который имя бота и коллбэк будет подаваться переменной, пример
<script async src="https://telegram.org/js/telegram-widget.js?14" data-telegram-login={ bot_login } data-size="large" data-auth-url={ auth_callback_url }></script>
PS: Подключая роутер использйте BrowserRouter
Нужно добавить eslint с airbnb конфигом
Сейчас статистика очень медленная, это от неправильно организации данных и не правильного сбора статистики.
В этом таске нужно:
Каждый пункт зависит от результатов предыдущего. Какие данные и как собирать обсудим лично и зафиксируем в комментариях.
План:
message_metrics
-------
id:serial
tg_id:int
timestamp:datetime
users_chats_id:int
photoCount:int
videoCount:int
questionCount: int
stickerSetName:string
textLength:int
voiceCount:int
lolReplyForUser:int
users
-----
id:serial
tg_id:int
first_name:string
last_name:string
chats
-----
id:serial
tg_id:int
name:string
users_chats
-----------
id:serial
user_id:int
chat_id:int
const fetchMetrics = (message) => {
return {
user: {
tg_id: 123,
first_name: 'asdf',
last_name: 'asdfsadf'
},
chat_id: {
tg_id: 123,
name: 123,
},
message_metrics: {
tg_id: 123,
photoCount: 0, // определяем наличие фото в сообщении как в contentSuppier
videoCount: 0, // определяем наличие видео в сообщении как в contentSuppier
questionCount: 0, // если в тексте есть вопрос, ставим 1 (осторожно urlы)
stickerSetName: 0,
textLength: 0,
voiceCount: 0, // ставим 1 если сообщение это голосуха
lolReplyForUser: 2, // humoristStat ищем в сообщениии реакцию смеха, и если она есть записываем сюда id юзера из реплая reply_to_message.from.id
}
};
};
Заметки:
https://www.lightbase.io/freeforlife/ - 500 мб бесплатно
Дудь (dud) — задал больше всех вопросов за все время в чате
В выводе /stats
, выделить заголовки строк жирным, названия стата и владельца ачивки
Например:
Сообщений за последние 24 часа: Aram Azbekian (52), Kirill Bobykin (25), Leonid Markizov (22), Katia Nokhrina (15), Ki Rill (15), 👨🏼💻 Stan Saal (13), Elizaveta Flisyuk (2), Сергей (2), Ilya Kovalenko (1)
Сообщений за последний час: Aram Azbekian (31), Kirill Bobykin (21), Leonid Markizov (17), Katia Nokhrina (6)
👨🏼💻 Stan Saal - безработный
Aram Azbekian - поставщик контента
Ki Rill - худший юзер чата
Пользователи иногда отправляют картинки из vk или видео с youtube. Если ссылка имеет расширение .jpg
или .png
или это ссылка на ютуб (короткая или длинная неважно) учитывать в ачивке
GET /api/chats/:id/stupid_achievments/:name?range_type=24h
- Возвращает статистку юзера
?range_type=24h
- отдать стат за последние 24 часа (Дефолтный range_type)?range_type=week
- отдать за неделю (аналогично ачивке недельного философа)?range_type=month
- отдать стат за последний месяц (аналогично ачивке недельного философа только за месяц, то есть находим первый день месяца и пляшем от него)?range_type=custom&range=2020-01-04_2020-01-06
- отдаем с начала дня старта периода, до конца дня конца периода включительно. Период надо провалидировать начало не должно быть позже конца.id, first_name, last_name, username, photo_url, auth_date, hash
забираем id. Это id телеграм юзера.{
"status": "ok",
"stupid_achievment": {
"name": "messages_count",
"data": [
{ "username": "Alexey Miroslavich", "value": 132 },
{ "username": "Dani Hood", "value": 121 }
]
}
}
chats/:id
или stupid_achievments/:name
несуществует или юзер не состоит в таком чате, отдаем{
"status": "error",
"message": "Can not find chat '12332'"
}
{
"status": "error",
"message": "Can not find stupid achievment 'asdf'"
}
?range_type=asdf&range=2020-01-06_2020-01-04
{
"status": "error",
"message": "Wrong 'range_type=asdf', please try one of 24h, week, month, custom"
}
?range_type=custom&range=2020-01-06_2020-01-04
{
"status": "error",
"message": "Wrong 'range=2020-01-06_2020-01-04', the beginning must be no later than the end"
}
{
"status": "forbidden",
"message": "Session is invalid, please sign in"
}
У нас есть пакет @shelf/jest-mongodb
. Он нужен чтобы при тестах установить mongodb и подключиться к ней, без монги бот не функционирует.
Тесты мы гоняем:
Пожалуйста, удалите этот пакет, перепишите job в github action через сервис.
Установка зависимостей, занимает ~2 минуты каждый раз, будет круто если мы закэшируем зависимости между джобами.
Гайд: https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows
В README.md не актуальный пример использования бота. Пожалуйста, сделайте gif c использованием бота
В gif должно быть использование команды /stats и ответ бота со всеми ачивками.
Если в чат прислали неизвестную боту команду, послать сообщение в чат с тесктом "Ты мне? Попробуй /stats"
Нужно написать отказ от претензий, в котором обозначается, что хоть мы и не передаем данные 3м лицам, но тем не менее не можем гарантировать приватность сообщений и использовать бота нужно на свой страх и риск.
Описание ошибки
При нескольких запусках тестов падали рандомные тесты с ошибкой BulkWriteError: E11000 duplicate key error collection: hakeshonassydb_test.messages index: id dup key: { _id: "5eb83823761f4f001183e8c1" }
Как повторить ошибку
Шаги с конкретными действиями:
Ожидаемое поведение
Стабильное прохождение всех тестов.
Заполни поля
Дизайн страницы: https://www.figma.com/file/cJUtYaG9QxcVZB9fFntQtt/Hake-Shonassy?node-id=2%3A2
Страница должна быть доступна по пути /stupid_achievements
, только залогиненым пользователям. У залогиненых пользователей есть сессия в cookies: в поле hake_session
есть json c полями id, first_name, last_name, username, photo_url, auth_date, hash. Если поле пусто - юзер не залогинен.
Данные для страницы получаем по ajax.
Поставщик контента (contentSupplier) - человек, который за последние 5 рабочих дней (с пн по пт) с 10:00 до 18:00 мск скинул больше всего видео или картинок.
У библиотеки slimbot мало функционала, нет возможности обращаться к telegram api. Необходимо заменить её на более зрелую, с возможностью работы с telegram api. Как вариант использовать node-telegram-bot-api (https://www.npmjs.com/package/node-telegram-bot-api).
Присваивается юзеру чата, который писал последний раз давнее всех
То есть находим последнее сообщение каждого юзера, затем выбираем самое ранее сообщение
Нужно написать авторизацию через телеграм, тут вся полезная инфа https://core.telegram.org/widgets/login
Авторизация через callback поэтому на бэке нужно реализовать пару методов:
GET /auth/callback?id=asdf&first_name=asdf&last_name=asdf&username=asdf&photo_url=asdf&auth_date=asdfhash=asdf
/?auth=success
/?auth=fail
GET /auth/logout
{ "message": "Bye!" }
Можно сделать тестовые welcome page и home page чтобы можно было протыкать весь процесс.
Философ чата (chatPhilosopher) — имеет самую большую медиану длины сообщения в чате. То есть считаем каждодому юзеру чата медиану, то у кого это самое большое число - философ.
Пример алгоритма медианы: https://repl.it/@qelphybox/jsmedianexample
Круто будет сделать одним агрегационным запросом в бд.
Алгоритм:
Каждому юзеру считаем длину каждого его сообщения от начала времен (значит нижняя граница не нужна, считаем по всем сообщениям). Для каждого юзера будет как бы массив длин сообщений { user1: [5,6,7,8,9, ...], ...}
Затем каждому юзеру находим медиану этого массива: получится например { user1: 9, ... }
Находим юзера с самым большим числом. Если их несколько, выводим всех.
вывод:
**username** - философ чата (345 сообщений по медиане)
// если несколько
**username1**, **username2** - философы чата (345 сообщений по медиане)
Ограничить выборку сообщений до месяца, но не так чтобы отсчёт был от текущей даты -30, а с первого дня каждого месяца. То есть сообщения написанные 30-31 числа прошлого месяца не учитывались.
Худший юзер чата (worstChatUser) - скинул больше всех голосовых сообщений в чат за все время.
GET /api/chats
- Отдает все чаты, в которых участвует юзер
id, first_name, last_name, username, photo_url, auth_date, hash
забираем id. Это id телеграм юзера.{
"status": "ok",
"chats": [
{ "title": "Группа 11б класса", "id": "123123" },
{ "title": "нг 2020", "id": "123124"}
]
}
{
"status": "forbidden"
}
Иногда юзеры пишут с ошибками и получается так, что у нас не актуальная бд.
Поэтому надо апдейтить сообщение по message.message_id
, перед этим хорошо будет сделать индекс { message_id: 1 }
Депендабот много спамит, надо постоянно заходить и говорить ему мерджить, хочу чтобы его пры автоматом мерджились, если прошли все проверки.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.