diff --git a/src/bots/factory/bots/approved/callback_data.ts b/src/bots/factory/bots/approved/callback_data.ts index 7c5936b..9ef9636 100644 --- a/src/bots/factory/bots/approved/callback_data.ts +++ b/src/bots/factory/bots/approved/callback_data.ts @@ -23,3 +23,5 @@ export const ENABLE_LANG_PREFIX = 'lang_on_'; export const DISABLE_LANG_PREFIX = 'lang_off_'; export const UPDATE_LOG_PREFIX = 'update_log_'; + +export const RATE_PREFIX = 'r_'; diff --git a/src/bots/factory/bots/approved/format.ts b/src/bots/factory/bots/approved/format.ts index 1266d99..0398be5 100644 --- a/src/bots/factory/bots/approved/format.ts +++ b/src/bots/factory/bots/approved/format.ts @@ -112,6 +112,11 @@ export function formatDetailBook(book: DetailBook): string { } +export function formatDetailBookWithRating(book: DetailBook): string { + return formatDetailBook(book) + '\n\n\nОценка:'; +} + + export function formatBookShort(book: AllBookTypes): string { return formatBook(book, true); } diff --git a/src/bots/factory/bots/approved/index.ts b/src/bots/factory/bots/approved/index.ts index a8832f3..8d29b3c 100644 --- a/src/bots/factory/bots/approved/index.ts +++ b/src/bots/factory/bots/approved/index.ts @@ -10,11 +10,12 @@ import * as Messages from "./messages"; import * as CallbackData from "./callback_data"; import * as BookLibrary from "./services/book_library"; +import * as Rating from "./services/book_ratings"; import UsersCounter from '@/analytics/users_counter'; import { createOrUpdateUserSettings, getUserOrDefaultLangCodes } from './services/user_settings'; -import { formatBook, formatBookShort, formatAuthor, formatSequence, formatTranslator, formatDetailBook } from './format'; +import { formatBook, formatBookShort, formatAuthor, formatSequence, formatTranslator, formatDetailBook, formatDetailBookWithRating } from './format'; import { getCallbackArgs, getPaginatedMessage, getPrefixWithQueryCreator, getSearchArgs, registerLanguageSettingsCallback, registerPaginationCommand, registerRandomItemCallback } from './utils'; -import { getRandomKeyboard, getTextPaginationData, getUpdateLogKeyboard, getUserAllowedLangsKeyboard } from './keyboard'; +import { getRandomKeyboard, getRatingKeyboard, getTextPaginationData, getUpdateLogKeyboard, getUserAllowedLangsKeyboard } from './keyboard'; import { sendFile } from './hooks/downloading'; import { setCommands } from './hooks/setCommands'; import { isNotModifiedMessage, isReplyMessageNotFound } from './errors_utils'; @@ -316,15 +317,38 @@ export async function createApprovedBot(token: string, state: BotState): Promise return; } - const bookId = ctx.message.text.split("@")[0].split('_')[2]; + const bookIdString = ctx.message.text.split("@")[0].split('_')[2]; + const bookId = parseInt(bookIdString); - const book = await BookLibrary.getBookById(parseInt(bookId)); + const book = await BookLibrary.getBookById(bookId); + const keyboard = await getRatingKeyboard(ctx.message.from.id, bookId, null); - await ctx.reply(formatDetailBook(book), { + await ctx.reply(formatDetailBookWithRating(book), { reply_to_message_id: ctx.message.message_id, + reply_markup: keyboard.reply_markup, }); }); + bot.action(new RegExp(CallbackData.RATE_PREFIX), async (ctx: Context) => { + if (!ctx.callbackQuery || !('data' in ctx.callbackQuery)) return; + + const queryData = ctx.callbackQuery.data.split("_"); + + const userId = parseInt(queryData[1]); + const bookId = parseInt(queryData[2]); + const rate = parseInt(queryData[3]); + + const rating = await Rating.set(userId, bookId, rate); + + const keyboard = await getRatingKeyboard(userId, bookId, rating); + + try { + await ctx.editMessageReplyMarkup( + keyboard.reply_markup + ); + } catch (e) {} + }); + bot.on("message", async (ctx: Context) => { if (!ctx.message || !('text' in ctx.message)) { return; diff --git a/src/bots/factory/bots/approved/keyboard.ts b/src/bots/factory/bots/approved/keyboard.ts index 41621f8..51d9787 100644 --- a/src/bots/factory/bots/approved/keyboard.ts +++ b/src/bots/factory/bots/approved/keyboard.ts @@ -3,8 +3,9 @@ import { InlineKeyboardMarkup } from 'typegram'; import moment from 'moment'; import chunkText from 'chunk-text'; -import { RANDOM_BOOK, RANDOM_AUTHOR, RANDOM_SEQUENCE, ENABLE_LANG_PREFIX, DISABLE_LANG_PREFIX, UPDATE_LOG_PREFIX } from './callback_data'; +import { RANDOM_BOOK, RANDOM_AUTHOR, RANDOM_SEQUENCE, ENABLE_LANG_PREFIX, DISABLE_LANG_PREFIX, UPDATE_LOG_PREFIX, RATE_PREFIX } from './callback_data'; import { getLanguages, getUserOrDefaultLangCodes } from './services/user_settings'; +import * as BookRating from "./services/book_ratings"; function getButtonLabel(delta: number, direction: 'left' | 'right'): string { @@ -117,3 +118,17 @@ export async function getUserAllowedLangsKeyboard(userId: number): Promise> { + const bookRating = rating ? rating : await BookRating.get(userId, bookId); + + const rate = bookRating ? bookRating.rate : null; + + return Markup.inlineKeyboard([ + [1, 2, 3, 4, 5].map((bRate) => { + const title = bRate === rate ? `⭐️ ${bRate}` : bRate.toString(); + + return Markup.button.callback(title, `${RATE_PREFIX}${userId}_${bookId}_${bRate}`); + }) + ]); +} diff --git a/src/bots/factory/bots/approved/services/book_ratings.ts b/src/bots/factory/bots/approved/services/book_ratings.ts new file mode 100644 index 0000000..ce00f93 --- /dev/null +++ b/src/bots/factory/bots/approved/services/book_ratings.ts @@ -0,0 +1,46 @@ +import got from 'got'; + +import env from '@/config'; + + +export interface Rating { + id: number; + user_id: number; + book_id: number; + rate: number; + updated: string; +} + + +export async function get(userId: number, bookId: number): Promise { + try { + const response = await got(`${env.RATINGS_URL}/api/v1/ratings/${userId}/${bookId}`, { + headers: { + 'Authorization': env.RATINGS_API_KEY, + }, + responseType: 'json', + }); + + return response.body; + } catch { + return null; + } +} + + +export async function set(userId: number, bookId: number, rate: number): Promise { + const response = await got.post(`${env.RATINGS_URL}/api/v1/ratings`, { + json: { + "user_id": userId, + "book_id": bookId, + "rate": rate, + }, + headers: { + 'Authorization': env.RATINGS_API_KEY, + 'Content-Type': 'application/json', + }, + responseType: 'json' + }); + + return response.body; +} diff --git a/src/config.ts b/src/config.ts index 91a749b..537a9bd 100644 --- a/src/config.ts +++ b/src/config.ts @@ -3,22 +3,35 @@ import { cleanEnv, str, num } from 'envalid'; export default cleanEnv(process.env, { SENTRY_DSN: str(), + WEBHOOK_BASE_URL: str(), WEBHOOK_PORT: num(), + TELEGRAM_BOT_API_ROOT: str({ default: "https://api.telegram.org" }), + MANAGER_URL: str(), MANAGER_API_KEY: str(), + BOOK_SERVER_URL: str(), BOOK_SERVER_API_KEY: str(), + CACHE_SERVER_URL: str(), CACHE_SERVER_API_KEY: str(), + BUFFER_SERVER_URL: str(), BUFFER_SERVER_API_KEY: str(), + DOWNLOADER_URL: str(), DOWNLOADER_API_KEY: str(), + USER_SETTINGS_URL: str(), USER_SETTINGS_API_KEY: str(), + + RATINGS_URL: str(), + RATINGS_API_KEY: str(), + NETWORK_IP_PREFIX: str(), + REDIS_HOST: str(), REDIS_PORT: num(), REDIS_DB: num(),