From dc91839abf735c87f0cc07b891df6261669fd0d2 Mon Sep 17 00:00:00 2001 From: Mohammad Honarvar Date: Fri, 25 Oct 2024 18:08:58 +0330 Subject: [PATCH 01/13] feat(notifier-api): add a new route to create a category --- packages/notifier-api/src/config.ts | 13 +++++++- .../src/handler/admin-validation.ts | 26 ++++++++++++++++ .../src/handler/category-title-validation.ts | 16 ++++++++++ .../notifier-api/src/lib/addNewCategory.ts | 19 ++++++++++++ packages/notifier-api/src/lib/hash.ts | 5 ++++ packages/notifier-api/src/main.ts | 1 + .../src/route/addNewCategoryRoute.ts | 26 ++++++++++++++++ packages/notifier-api/src/type.ts | 5 ++++ yarn.lock | 30 +++++++++---------- 9 files changed, 125 insertions(+), 16 deletions(-) create mode 100644 packages/notifier-api/src/handler/admin-validation.ts create mode 100644 packages/notifier-api/src/handler/category-title-validation.ts create mode 100644 packages/notifier-api/src/lib/addNewCategory.ts create mode 100644 packages/notifier-api/src/lib/hash.ts create mode 100644 packages/notifier-api/src/route/addNewCategoryRoute.ts diff --git a/packages/notifier-api/src/config.ts b/packages/notifier-api/src/config.ts index 1737c3e9..f8e19367 100644 --- a/packages/notifier-api/src/config.ts +++ b/packages/notifier-api/src/config.ts @@ -1,7 +1,7 @@ import {createLogger, packageTracer} from 'alwatr/nanolib'; import {Region, StoreFileType, type AlwatrNitrobaseConfig, type StoreFileStat} from 'alwatr/nitrobase'; -import type {NanotronApiServerConfig} from 'alwatr/nanotron'; +import type {NanotronApiServerConfig, HashGeneratorConfig} from 'alwatr/nanotron'; import type {PollingOptions, ApiClientOptions} from 'grammy'; __dev_mode__: packageTracer.add(__package_name__, __package_version__); @@ -19,6 +19,8 @@ const env = /* #__PURE__ */ (() => { botFirstName: 'BOT_FIRST_NAME', dropPendingUpdates: '1', botAdminChatId: 'ADMIN_CHAT_ID', + adminToken: 'ADMIN_TOKEN', + } as const; const env_ = { @@ -35,6 +37,8 @@ const env = /* #__PURE__ */ (() => { })(); export const config = { + adminToken: env.adminToken!, + nanotronApiServer: { host: env.host!, port: +env.port!, @@ -61,6 +65,13 @@ export const config = { allowed_updates: ['message'], } as PollingOptions, } as const, + + hashGenerator: { + algorithm: 'sha1', + crcLength: 3, + encoding: 'hex', + prefix: 'ca' // caTEGORY + } as HashGeneratorConfig, } as const; __dev_mode__: logger.logProperty?.('config', config); diff --git a/packages/notifier-api/src/handler/admin-validation.ts b/packages/notifier-api/src/handler/admin-validation.ts new file mode 100644 index 00000000..8f7d09c7 --- /dev/null +++ b/packages/notifier-api/src/handler/admin-validation.ts @@ -0,0 +1,26 @@ +import {HttpStatusCodes, type NanotronClientRequest} from 'alwatr/nanotron'; + +import {config, logger} from '../config.js'; + +export async function adminValidation(this: NanotronClientRequest<{body: JsonObject}>): Promise { + logger.logMethodArgs?.('adminValidation', {body: this.sharedMeta.body}); + + if (this.sharedMeta.body.adminToken === undefined || typeof this.sharedMeta.body.adminToken !== 'string') { + this.serverResponse.statusCode = HttpStatusCodes.Error_Client_400_Bad_Request; + this.serverResponse.replyJson({ + ok: false, + errorCode: 'invalid_body_params_format', + errorMessage: 'Invalid body params', + }); + return; + } + + if (this.sharedMeta.body.adminToken !== config.adminToken) { + this.serverResponse.statusCode = HttpStatusCodes.Error_Client_403_Forbidden; + this.serverResponse.replyJson({ + ok: false, + errorCode: 'invalid_admin_token', + errorMessage: 'Token is invalid.', + }); + } +} diff --git a/packages/notifier-api/src/handler/category-title-validation.ts b/packages/notifier-api/src/handler/category-title-validation.ts new file mode 100644 index 00000000..3a5920ca --- /dev/null +++ b/packages/notifier-api/src/handler/category-title-validation.ts @@ -0,0 +1,16 @@ +import {HttpStatusCodes, type NanotronClientRequest} from 'alwatr/nanotron'; + +import {logger} from '../config.js'; + +export async function categoryTitleValidation(this: NanotronClientRequest<{body: JsonObject}>): Promise { + logger.logMethodArgs?.('categoryTitleValidation', {body: this.sharedMeta.body}); + + if (this.sharedMeta.body.title === undefined || typeof this.sharedMeta.body.title !== 'string') { + this.serverResponse.statusCode = HttpStatusCodes.Error_Client_400_Bad_Request; + this.serverResponse.replyJson({ + ok: false, + errorCode: 'invalid_body_params_format', + errorMessage: 'The title of category is invalid.', + }); + } +} diff --git a/packages/notifier-api/src/lib/addNewCategory.ts b/packages/notifier-api/src/lib/addNewCategory.ts new file mode 100644 index 00000000..385c7687 --- /dev/null +++ b/packages/notifier-api/src/lib/addNewCategory.ts @@ -0,0 +1,19 @@ +import {config, logger} from '../config.js'; +import {hashGenerator} from './hash.js'; +import {nitrobase} from './nitrobase.js'; + +import type {Category} from '../type.js'; + +export async function addNewCategory(title: string): Promise { + logger.logMethodArgs?.('addNewCategory', title); + + const categoriesCollection = await nitrobase.openCollection(config.nitrobase.categoriesCollection); + + const categoryId = hashGenerator.generateSelfValidate(title); + categoriesCollection.addItem(categoryId, { + title, + members: [] + }); + + categoriesCollection.save(); +} diff --git a/packages/notifier-api/src/lib/hash.ts b/packages/notifier-api/src/lib/hash.ts new file mode 100644 index 00000000..5d149d55 --- /dev/null +++ b/packages/notifier-api/src/lib/hash.ts @@ -0,0 +1,5 @@ +import {AlwatrHashGenerator} from 'alwatr/nanotron'; + +import {config} from '../config.js'; + +export const hashGenerator = new AlwatrHashGenerator(config.hashGenerator); diff --git a/packages/notifier-api/src/main.ts b/packages/notifier-api/src/main.ts index 8980c3d1..44355aa8 100644 --- a/packages/notifier-api/src/main.ts +++ b/packages/notifier-api/src/main.ts @@ -2,6 +2,7 @@ import './command/start-command.js'; import {logger} from './config.js'; import {startBot} from './lib/bot.js'; import {initializeNitrobase} from './lib/initialize-nitrobase.js'; +import './route/addNewCategoryRoute.js'; import './route/home.js'; import './route/notifyRoute.js'; diff --git a/packages/notifier-api/src/route/addNewCategoryRoute.ts b/packages/notifier-api/src/route/addNewCategoryRoute.ts new file mode 100644 index 00000000..f2507d54 --- /dev/null +++ b/packages/notifier-api/src/route/addNewCategoryRoute.ts @@ -0,0 +1,26 @@ +import {logger} from '../config.js'; +import {adminValidation} from '../handler/admin-validation.js'; +import {categoryTitleValidation} from '../handler/category-title-validation.js'; +import {parseBodyAsJson} from '../handler/parse-body-as-json.js'; +import {addNewCategory} from '../lib/addNewCategory.js'; +import {nanotronApiServer} from '../lib/server.js'; + +import type {AddNewCategoryOption} from '../type.js'; + +nanotronApiServer.defineRoute<{body: AddNewCategoryOption}>({ + method: 'PUT', + url: 'add-new-category', + preHandlers: [parseBodyAsJson, adminValidation, categoryTitleValidation], + async handler() { + logger.logMethod?.('addNewCategoryRoute'); + + await addNewCategory(this.sharedMeta.body.title); + + this.serverResponse.replyJson({ + ok: true, + data: { + title: this.sharedMeta.body.title + } + }); + }, +}); diff --git a/packages/notifier-api/src/type.ts b/packages/notifier-api/src/type.ts index 639daa73..d45d6f77 100644 --- a/packages/notifier-api/src/type.ts +++ b/packages/notifier-api/src/type.ts @@ -17,3 +17,8 @@ export type NotifyOption = { message: string; markdown: boolean; }; + +export type AddNewCategoryOption = { + title: string; + adminToken: string; +} diff --git a/yarn.lock b/yarn.lock index fd190e42..60167540 100644 --- a/yarn.lock +++ b/yarn.lock @@ -323,21 +323,6 @@ __metadata: languageName: node linkType: hard -"@alwatr/notifier-api@workspace:packages/notifier-api": - version: 0.0.0-use.local - resolution: "@alwatr/notifier-api@workspace:packages/notifier-api" - dependencies: - "@alwatr/nano-build": "npm:^2.0.2" - "@alwatr/prettier-config": "npm:^1.0.6" - "@alwatr/tsconfig-base": "npm:^1.3.2" - "@alwatr/type-helper": "npm:^2.0.2" - "@types/node": "npm:^22.7.7" - alwatr: "npm:^2.0.3" - grammy: "npm:^1.30.0" - typescript: "npm:^5.6.3" - languageName: unknown - linkType: soft - "@alwatr/observable@npm:^3.2.0": version: 3.2.0 resolution: "@alwatr/observable@npm:3.2.0" @@ -8349,6 +8334,21 @@ __metadata: languageName: node linkType: hard +"telegram-notifier@workspace:packages/notifier-api": + version: 0.0.0-use.local + resolution: "telegram-notifier@workspace:packages/notifier-api" + dependencies: + "@alwatr/nano-build": "npm:^2.0.2" + "@alwatr/prettier-config": "npm:^1.0.6" + "@alwatr/tsconfig-base": "npm:^1.3.2" + "@alwatr/type-helper": "npm:^2.0.2" + "@types/node": "npm:^22.7.7" + alwatr: "npm:^2.0.3" + grammy: "npm:^1.30.0" + typescript: "npm:^5.6.3" + languageName: unknown + linkType: soft + "temp-dir@npm:^3.0.0": version: 3.0.0 resolution: "temp-dir@npm:3.0.0" From da6b6e9c86a2b85872b6683508f366633aa1084b Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Fri, 25 Oct 2024 19:34:13 +0330 Subject: [PATCH 02/13] refactor: rename files --- .../notifier-api/src/lib/{notifyTelegram.ts => notify.ts} | 2 +- packages/notifier-api/src/main.ts | 2 +- packages/notifier-api/src/route/{notifyRoute.ts => notify.ts} | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename packages/notifier-api/src/lib/{notifyTelegram.ts => notify.ts} (94%) rename packages/notifier-api/src/route/{notifyRoute.ts => notify.ts} (84%) diff --git a/packages/notifier-api/src/lib/notifyTelegram.ts b/packages/notifier-api/src/lib/notify.ts similarity index 94% rename from packages/notifier-api/src/lib/notifyTelegram.ts rename to packages/notifier-api/src/lib/notify.ts index ecf94139..ee6bd2dc 100644 --- a/packages/notifier-api/src/lib/notifyTelegram.ts +++ b/packages/notifier-api/src/lib/notify.ts @@ -8,7 +8,7 @@ import type {GrammyError} from 'grammy'; /** * Send a message to all members of the `categoryId`. */ -export async function notifyTelegram(option: NotifyOption): Promise { +export async function notify(option: NotifyOption): Promise { logger.logMethodArgs?.('notifyTelegram', option); const categoriesCollection = await nitrobase.openCollection(config.nitrobase.categoriesCollection); const members = categoriesCollection.getItemData(option.categoryId).members; diff --git a/packages/notifier-api/src/main.ts b/packages/notifier-api/src/main.ts index 44355aa8..be206474 100644 --- a/packages/notifier-api/src/main.ts +++ b/packages/notifier-api/src/main.ts @@ -4,7 +4,7 @@ import {startBot} from './lib/bot.js'; import {initializeNitrobase} from './lib/initialize-nitrobase.js'; import './route/addNewCategoryRoute.js'; import './route/home.js'; -import './route/notifyRoute.js'; +import './route/notify.js'; logger.banner(__package_name__); diff --git a/packages/notifier-api/src/route/notifyRoute.ts b/packages/notifier-api/src/route/notify.ts similarity index 84% rename from packages/notifier-api/src/route/notifyRoute.ts rename to packages/notifier-api/src/route/notify.ts index 2f59c150..c88b3bd9 100644 --- a/packages/notifier-api/src/route/notifyRoute.ts +++ b/packages/notifier-api/src/route/notify.ts @@ -1,7 +1,7 @@ import {logger} from '../config.js'; import {notifyValidation} from '../handler/notify-validation.js'; import {parseBodyAsJson} from '../handler/parse-body-as-json.js'; -import {notifyTelegram} from '../lib/notifyTelegram.js'; +import {notify} from '../lib/notify.js'; import {nanotronApiServer} from '../lib/server.js'; import type {NotifyOption} from '../type.js'; @@ -14,7 +14,7 @@ nanotronApiServer.defineRoute<{body: NotifyOption}>({ logger.logMethod?.('notifyRoute'); const notifyOption = this.sharedMeta.body; - notifyTelegram(notifyOption); // no need to await + notify(notifyOption); // no need to await this.serverResponse.replyJson({ ok: true, From 2a3cbd0c7b402f900ab4e1e91bd5623a6059f1c3 Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Fri, 25 Oct 2024 20:40:08 +0330 Subject: [PATCH 03/13] refactor(start-command): review and enhance --- packages/notifier-api/src/command/start-command.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/notifier-api/src/command/start-command.ts b/packages/notifier-api/src/command/start-command.ts index a1840d96..a443e0cd 100644 --- a/packages/notifier-api/src/command/start-command.ts +++ b/packages/notifier-api/src/command/start-command.ts @@ -1,7 +1,7 @@ import {config, logger} from '../config.js'; import {bot} from '../lib/bot.js'; import {message} from '../lib/message.js'; -import {nitrobase} from '../lib/nitrobase.js'; +import {openCategoryCollection, nitrobase} from '../lib/nitrobase.js'; import type {Category} from '../type.js'; @@ -31,9 +31,9 @@ bot.command( return; } - const categoriesCollection = await nitrobase.openCollection(config.nitrobase.categoriesCollection); + const categoryCollection = await openCategoryCollection(); - if (categoriesCollection.hasItem(categoryId) === false) { + if (categoryCollection.hasItem(categoryId) === false) { logger.incident?.('startCommand', 'category_not_found', {categoryId, from: ctx.from, chat: ctx.chat}); await ctx.reply(message.invalid_data_submitted, { reply_parameters: { @@ -43,7 +43,7 @@ bot.command( return; } - const members = categoriesCollection.getItemData(categoryId).members; + const members = categoryCollection.getItemData(categoryId).members; if (members.findIndex((member) => member.id === ctx.chat.id) !== -1) { await ctx.reply(message.already_added_to_list); @@ -58,7 +58,7 @@ bot.command( lastName: ctx.chat.last_name, username: ctx.chat.username, }); - categoriesCollection.save(); + categoryCollection.save(); await ctx.reply(message.success_added_to_list); } From f32868eb5465e7fc651a633be36f9bcd1916b978 Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Fri, 25 Oct 2024 20:40:52 +0330 Subject: [PATCH 04/13] refactor(db): review and enhance --- packages/notifier-api/src/config.ts | 2 +- packages/notifier-api/src/lib/initialize-nitrobase.ts | 4 ++-- packages/notifier-api/src/lib/nitrobase.ts | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/notifier-api/src/config.ts b/packages/notifier-api/src/config.ts index f8e19367..a7b4304c 100644 --- a/packages/notifier-api/src/config.ts +++ b/packages/notifier-api/src/config.ts @@ -50,7 +50,7 @@ export const config = { rootPath: env.dbPath!, } as AlwatrNitrobaseConfig, - categoriesCollection: { + categoryCollection: { name: 'categories', region: Region.Managers, type: StoreFileType.Collection, diff --git a/packages/notifier-api/src/lib/initialize-nitrobase.ts b/packages/notifier-api/src/lib/initialize-nitrobase.ts index 9f2f605b..40f3bf66 100644 --- a/packages/notifier-api/src/lib/initialize-nitrobase.ts +++ b/packages/notifier-api/src/lib/initialize-nitrobase.ts @@ -2,7 +2,7 @@ import {config} from '../config.js'; import {nitrobase} from './nitrobase.js'; export function initializeNitrobase() { - if (nitrobase.hasStore(config.nitrobase.categoriesCollection) === false) { - nitrobase.newCollection(config.nitrobase.categoriesCollection); + if (nitrobase.hasStore(config.nitrobase.categoryCollection) === false) { + nitrobase.newCollection(config.nitrobase.categoryCollection); } } diff --git a/packages/notifier-api/src/lib/nitrobase.ts b/packages/notifier-api/src/lib/nitrobase.ts index bd48a197..6bb41ca6 100644 --- a/packages/notifier-api/src/lib/nitrobase.ts +++ b/packages/notifier-api/src/lib/nitrobase.ts @@ -2,4 +2,8 @@ import {AlwatrNitrobase} from 'alwatr/nitrobase'; import {config} from '../config.js'; +import type {Category} from '../type.js'; + export const nitrobase = new AlwatrNitrobase(config.nitrobase.config); + +export const openCategoryCollection = async () => await nitrobase.openCollection(config.nitrobase.categoryCollection); From adb18f55a5c6d7dd0525a80762cc448212ad10b5 Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Fri, 25 Oct 2024 20:41:28 +0330 Subject: [PATCH 05/13] refactor(notify): review and enhance --- .../src/handler/notify-validation.ts | 51 ----------------- .../src/lib/{notify.ts => telegram-notify.ts} | 25 ++++---- packages/notifier-api/src/route/notify.ts | 57 +++++++++++++++++-- 3 files changed, 66 insertions(+), 67 deletions(-) delete mode 100644 packages/notifier-api/src/handler/notify-validation.ts rename packages/notifier-api/src/lib/{notify.ts => telegram-notify.ts} (55%) diff --git a/packages/notifier-api/src/handler/notify-validation.ts b/packages/notifier-api/src/handler/notify-validation.ts deleted file mode 100644 index 588916d3..00000000 --- a/packages/notifier-api/src/handler/notify-validation.ts +++ /dev/null @@ -1,51 +0,0 @@ -import {HttpStatusCodes, type NanotronClientRequest} from 'alwatr/nanotron'; - -import {config, logger} from '../config.js'; -import {nitrobase} from '../lib/nitrobase.js'; - -import type {Category, NotifyOption} from '../type.js'; - -export async function notifyValidation(this: NanotronClientRequest<{body: JsonObject}>): Promise { - logger.logMethodArgs?.('notifyValidation', {body: this.sharedMeta.body}); - - const {categoryId, message, markdown} = this.sharedMeta.body; - - if (categoryId === undefined || typeof categoryId !== 'string') { - this.serverResponse.statusCode = HttpStatusCodes.Error_Client_400_Bad_Request; - this.serverResponse.replyJson({ - ok: false, - errorCode: 'category_required', - errorMessage: 'Category is required.', - }); - return; - } - - if (message === undefined || typeof message !== 'string') { - this.serverResponse.statusCode = HttpStatusCodes.Error_Client_400_Bad_Request; - this.serverResponse.replyJson({ - ok: false, - errorCode: 'message_required', - errorMessage: 'Message is required.', - }); - return; - } - - const categoriesCollection = await nitrobase.openCollection(config.nitrobase.categoriesCollection); - - if (categoriesCollection.hasItem(categoryId) === false) { - this.serverResponse.statusCode = HttpStatusCodes.Error_Client_400_Bad_Request; - this.serverResponse.replyJson({ - ok: false, - errorCode: 'category_not_found', - errorMessage: 'Category not found.', - }); - return; - } - - // just for type validation - (this.sharedMeta.body as NotifyOption) = { - categoryId, - message, - markdown: markdown === true, - }; -} diff --git a/packages/notifier-api/src/lib/notify.ts b/packages/notifier-api/src/lib/telegram-notify.ts similarity index 55% rename from packages/notifier-api/src/lib/notify.ts rename to packages/notifier-api/src/lib/telegram-notify.ts index ee6bd2dc..6c9fab25 100644 --- a/packages/notifier-api/src/lib/notify.ts +++ b/packages/notifier-api/src/lib/telegram-notify.ts @@ -1,17 +1,22 @@ -import {config, logger} from '../config.js'; +import {logger} from '../config.js'; import {bot} from './bot.js'; -import {nitrobase} from './nitrobase.js'; +import {openCategoryCollection} from './nitrobase.js'; -import type {Category, NotifyOption} from '../type.js'; import type {GrammyError} from 'grammy'; +export type TelegramNotifyOption = { + categoryId: string; + message: string; + markdown: boolean; +} + /** * Send a message to all members of the `categoryId`. */ -export async function notify(option: NotifyOption): Promise { - logger.logMethodArgs?.('notifyTelegram', option); - const categoriesCollection = await nitrobase.openCollection(config.nitrobase.categoriesCollection); - const members = categoriesCollection.getItemData(option.categoryId).members; +export async function telegramNotify(option: TelegramNotifyOption): Promise { + logger.logMethodArgs?.('telegramNotify', option); + const categoryCollection = await openCategoryCollection(); + const members = categoryCollection.getItemData(option.categoryId).members; for (let i = members.length - 1; i >= 0; i--) { const member = members[i]; try { @@ -27,12 +32,12 @@ export async function notify(option: NotifyOption): Promise { if (error.error_code === 403) { const memberIndex = members.indexOf(member); if (memberIndex === -1) { - logger.accident?.('notifyTelegram', 'unexpected_member_not_found_to_remove', {member, members}); + logger.accident?.('telegramNotify', 'unexpected_member_not_found_to_remove', {member, members}); } members.splice(memberIndex, 1); - categoriesCollection.save(); + categoryCollection.save(); } } } - logger.logStep?.('notify', 'done'); + logger.logStep?.('telegramNotify', 'done'); } diff --git a/packages/notifier-api/src/route/notify.ts b/packages/notifier-api/src/route/notify.ts index c88b3bd9..cd2688d7 100644 --- a/packages/notifier-api/src/route/notify.ts +++ b/packages/notifier-api/src/route/notify.ts @@ -1,12 +1,12 @@ +import {HttpStatusCodes, type NanotronClientRequest} from 'alwatr/nanotron'; + import {logger} from '../config.js'; -import {notifyValidation} from '../handler/notify-validation.js'; import {parseBodyAsJson} from '../handler/parse-body-as-json.js'; -import {notify} from '../lib/notify.js'; +import { openCategoryCollection } from '../lib/nitrobase.js'; import {nanotronApiServer} from '../lib/server.js'; +import {telegramNotify, type TelegramNotifyOption} from '../lib/telegram-notify.js'; -import type {NotifyOption} from '../type.js'; - -nanotronApiServer.defineRoute<{body: NotifyOption}>({ +nanotronApiServer.defineRoute<{body: TelegramNotifyOption}>({ method: 'POST', url: 'notify', preHandlers: [parseBodyAsJson, notifyValidation], @@ -14,10 +14,55 @@ nanotronApiServer.defineRoute<{body: NotifyOption}>({ logger.logMethod?.('notifyRoute'); const notifyOption = this.sharedMeta.body; - notify(notifyOption); // no need to await + telegramNotify(notifyOption); // no need to await this.serverResponse.replyJson({ ok: true, }); }, }); + +export async function notifyValidation(this: NanotronClientRequest<{body: JsonObject}>): Promise { + const {categoryId, message, markdown} = this.sharedMeta.body; + + logger.logMethodArgs?.('notifyValidation', {categoryId, message, markdown}); + + if (categoryId === undefined || typeof categoryId !== 'string') { + this.serverResponse.statusCode = HttpStatusCodes.Error_Client_400_Bad_Request; + this.serverResponse.replyJson({ + ok: false, + errorCode: 'category_required', + errorMessage: 'Category is required.', + }); + return; + } + + if (message === undefined || typeof message !== 'string') { + this.serverResponse.statusCode = HttpStatusCodes.Error_Client_400_Bad_Request; + this.serverResponse.replyJson({ + ok: false, + errorCode: 'message_required', + errorMessage: 'Message is required.', + }); + return; + } + + const categoryCollection = await openCategoryCollection(); + + if (categoryCollection.hasItem(categoryId) === false) { + this.serverResponse.statusCode = HttpStatusCodes.Error_Client_400_Bad_Request; + this.serverResponse.replyJson({ + ok: false, + errorCode: 'category_not_found', + errorMessage: `Category ${categoryId} not found.`, + }); + return; + } + + // just for type validation and cleanup extra + (this.sharedMeta.body as TelegramNotifyOption) = { + categoryId, + message, + markdown: markdown === true, + }; +} From f83c301211c97cf8fd3ed0594a84d641798cfcb2 Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Fri, 25 Oct 2024 20:42:04 +0330 Subject: [PATCH 06/13] refactor(new-category): rewrite new category route --- .../src/handler/category-title-validation.ts | 16 ---- .../notifier-api/src/lib/addNewCategory.ts | 19 ----- .../src/route/addNewCategoryRoute.ts | 26 ------ .../notifier-api/src/route/new-category.ts | 79 +++++++++++++++++++ 4 files changed, 79 insertions(+), 61 deletions(-) delete mode 100644 packages/notifier-api/src/handler/category-title-validation.ts delete mode 100644 packages/notifier-api/src/lib/addNewCategory.ts delete mode 100644 packages/notifier-api/src/route/addNewCategoryRoute.ts create mode 100644 packages/notifier-api/src/route/new-category.ts diff --git a/packages/notifier-api/src/handler/category-title-validation.ts b/packages/notifier-api/src/handler/category-title-validation.ts deleted file mode 100644 index 3a5920ca..00000000 --- a/packages/notifier-api/src/handler/category-title-validation.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {HttpStatusCodes, type NanotronClientRequest} from 'alwatr/nanotron'; - -import {logger} from '../config.js'; - -export async function categoryTitleValidation(this: NanotronClientRequest<{body: JsonObject}>): Promise { - logger.logMethodArgs?.('categoryTitleValidation', {body: this.sharedMeta.body}); - - if (this.sharedMeta.body.title === undefined || typeof this.sharedMeta.body.title !== 'string') { - this.serverResponse.statusCode = HttpStatusCodes.Error_Client_400_Bad_Request; - this.serverResponse.replyJson({ - ok: false, - errorCode: 'invalid_body_params_format', - errorMessage: 'The title of category is invalid.', - }); - } -} diff --git a/packages/notifier-api/src/lib/addNewCategory.ts b/packages/notifier-api/src/lib/addNewCategory.ts deleted file mode 100644 index 385c7687..00000000 --- a/packages/notifier-api/src/lib/addNewCategory.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {config, logger} from '../config.js'; -import {hashGenerator} from './hash.js'; -import {nitrobase} from './nitrobase.js'; - -import type {Category} from '../type.js'; - -export async function addNewCategory(title: string): Promise { - logger.logMethodArgs?.('addNewCategory', title); - - const categoriesCollection = await nitrobase.openCollection(config.nitrobase.categoriesCollection); - - const categoryId = hashGenerator.generateSelfValidate(title); - categoriesCollection.addItem(categoryId, { - title, - members: [] - }); - - categoriesCollection.save(); -} diff --git a/packages/notifier-api/src/route/addNewCategoryRoute.ts b/packages/notifier-api/src/route/addNewCategoryRoute.ts deleted file mode 100644 index f2507d54..00000000 --- a/packages/notifier-api/src/route/addNewCategoryRoute.ts +++ /dev/null @@ -1,26 +0,0 @@ -import {logger} from '../config.js'; -import {adminValidation} from '../handler/admin-validation.js'; -import {categoryTitleValidation} from '../handler/category-title-validation.js'; -import {parseBodyAsJson} from '../handler/parse-body-as-json.js'; -import {addNewCategory} from '../lib/addNewCategory.js'; -import {nanotronApiServer} from '../lib/server.js'; - -import type {AddNewCategoryOption} from '../type.js'; - -nanotronApiServer.defineRoute<{body: AddNewCategoryOption}>({ - method: 'PUT', - url: 'add-new-category', - preHandlers: [parseBodyAsJson, adminValidation, categoryTitleValidation], - async handler() { - logger.logMethod?.('addNewCategoryRoute'); - - await addNewCategory(this.sharedMeta.body.title); - - this.serverResponse.replyJson({ - ok: true, - data: { - title: this.sharedMeta.body.title - } - }); - }, -}); diff --git a/packages/notifier-api/src/route/new-category.ts b/packages/notifier-api/src/route/new-category.ts new file mode 100644 index 00000000..34f21895 --- /dev/null +++ b/packages/notifier-api/src/route/new-category.ts @@ -0,0 +1,79 @@ +import {HttpStatusCodes, type NanotronClientRequest} from 'alwatr/nanotron'; + +import {logger} from '../config.js'; +import {parseBodyAsJson} from '../handler/parse-body-as-json.js'; +import {bot} from '../lib/bot.js'; +import {openCategoryCollection} from '../lib/nitrobase.js'; +import {nanotronApiServer} from '../lib/server.js'; + +export type NewCategoryOption = { + id: string; + title: string; +}; + +nanotronApiServer.defineRoute<{body: NewCategoryOption}>({ + method: 'POST', + url: 'new-category', + preHandlers: [parseBodyAsJson, newCategoryValidation], + async handler() { + logger.logMethod?.('newCategoryRoute'); + + const {id, title} = this.sharedMeta.body; + + const categoryCollection = await openCategoryCollection(); + + categoryCollection.addItem(id, {title, members: []}); + + const botInfo = bot.botInfo; + + this.serverResponse.replyJson({ + ok: true, + data: { + subscribe: `https://t.me/${botInfo.username}?start=${id}`, + }, + }); + }, +}); + +export async function newCategoryValidation(this: NanotronClientRequest<{body: JsonObject}>): Promise { + const {id, title} = this.sharedMeta.body; + logger.logMethodArgs?.('newCategoryValidation', {id, title}); + + if (title === undefined || typeof title !== 'string') { + this.serverResponse.statusCode = HttpStatusCodes.Error_Client_400_Bad_Request; + this.serverResponse.replyJson({ + ok: false, + errorCode: 'title_required', + errorMessage: 'Title is required.', + }); + return; + } + + if (id === undefined || typeof id !== 'string') { + this.serverResponse.statusCode = HttpStatusCodes.Error_Client_400_Bad_Request; + this.serverResponse.replyJson({ + ok: false, + errorCode: 'id_required', + errorMessage: 'Id is required.', + }); + return; + } + + const categoryCollection = await openCategoryCollection(); + + if (categoryCollection.hasItem(id)) { + this.serverResponse.statusCode = HttpStatusCodes.Error_Client_400_Bad_Request; + this.serverResponse.replyJson({ + ok: false, + errorCode: 'category_exist', + errorMessage: `Category ${id} already exist.`, + }); + return; + } + + // just for type validation and cleanup extra + (this.sharedMeta.body as NewCategoryOption) = { + id, + title, + }; +} From e5af06e73a335b06fb1d8d9de9493486298b2358 Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Fri, 25 Oct 2024 20:42:37 +0330 Subject: [PATCH 07/13] chore: cleanup --- packages/notifier-api/src/main.ts | 2 +- packages/notifier-api/src/type.ts | 11 ----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/packages/notifier-api/src/main.ts b/packages/notifier-api/src/main.ts index be206474..99fae0a5 100644 --- a/packages/notifier-api/src/main.ts +++ b/packages/notifier-api/src/main.ts @@ -2,8 +2,8 @@ import './command/start-command.js'; import {logger} from './config.js'; import {startBot} from './lib/bot.js'; import {initializeNitrobase} from './lib/initialize-nitrobase.js'; -import './route/addNewCategoryRoute.js'; import './route/home.js'; +import './route/new-category.js'; import './route/notify.js'; logger.banner(__package_name__); diff --git a/packages/notifier-api/src/type.ts b/packages/notifier-api/src/type.ts index d45d6f77..e4611c13 100644 --- a/packages/notifier-api/src/type.ts +++ b/packages/notifier-api/src/type.ts @@ -11,14 +11,3 @@ export type Member = { firstName?: string; lastName?: string; }; - -export type NotifyOption = { - categoryId: string; - message: string; - markdown: boolean; -}; - -export type AddNewCategoryOption = { - title: string; - adminToken: string; -} From 6b0961b91e0a2f0238b3c1346e9406af93abef34 Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Fri, 25 Oct 2024 21:56:58 +0330 Subject: [PATCH 08/13] feat: requireAccessToken handler --- .../src/handler/admin-validation.ts | 26 ----------------- .../src/handler/require-access-token.ts | 28 +++++++++++++++++++ 2 files changed, 28 insertions(+), 26 deletions(-) delete mode 100644 packages/notifier-api/src/handler/admin-validation.ts create mode 100644 packages/notifier-api/src/handler/require-access-token.ts diff --git a/packages/notifier-api/src/handler/admin-validation.ts b/packages/notifier-api/src/handler/admin-validation.ts deleted file mode 100644 index 8f7d09c7..00000000 --- a/packages/notifier-api/src/handler/admin-validation.ts +++ /dev/null @@ -1,26 +0,0 @@ -import {HttpStatusCodes, type NanotronClientRequest} from 'alwatr/nanotron'; - -import {config, logger} from '../config.js'; - -export async function adminValidation(this: NanotronClientRequest<{body: JsonObject}>): Promise { - logger.logMethodArgs?.('adminValidation', {body: this.sharedMeta.body}); - - if (this.sharedMeta.body.adminToken === undefined || typeof this.sharedMeta.body.adminToken !== 'string') { - this.serverResponse.statusCode = HttpStatusCodes.Error_Client_400_Bad_Request; - this.serverResponse.replyJson({ - ok: false, - errorCode: 'invalid_body_params_format', - errorMessage: 'Invalid body params', - }); - return; - } - - if (this.sharedMeta.body.adminToken !== config.adminToken) { - this.serverResponse.statusCode = HttpStatusCodes.Error_Client_403_Forbidden; - this.serverResponse.replyJson({ - ok: false, - errorCode: 'invalid_admin_token', - errorMessage: 'Token is invalid.', - }); - } -} diff --git a/packages/notifier-api/src/handler/require-access-token.ts b/packages/notifier-api/src/handler/require-access-token.ts new file mode 100644 index 00000000..51a1a81e --- /dev/null +++ b/packages/notifier-api/src/handler/require-access-token.ts @@ -0,0 +1,28 @@ +import {HttpStatusCodes, type NanotronClientRequest} from 'alwatr/nanotron'; + +import {config, logger} from '../config.js'; +import { getAuthBearer } from '../lib/get-auth-bearer.js'; + +export async function requireAccessToken(this: NanotronClientRequest): Promise { + const token = getAuthBearer(this.headers.authorization); + logger.logMethodArgs?.('requireAccessToken', {token}); + + if (token === null) { + this.serverResponse.statusCode = HttpStatusCodes.Error_Client_401_Unauthorized; + this.serverResponse.replyErrorResponse({ + ok: false, + errorCode: 'authorization_required', + errorMessage: 'Authorization token required' + }); + return; + } + + if (token !== config.accessToken) { + this.serverResponse.statusCode = HttpStatusCodes.Error_Client_403_Forbidden; + this.serverResponse.replyErrorResponse({ + ok: false, + errorCode: 'access_denied', + errorMessage: 'Access denied, token is invalid!', + }); + } +} From 836ac0cded9995689e7703927eb230faeb6c4830 Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Fri, 25 Oct 2024 21:57:08 +0330 Subject: [PATCH 09/13] feat: getAuthBearer --- packages/notifier-api/src/lib/get-auth-bearer.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 packages/notifier-api/src/lib/get-auth-bearer.ts diff --git a/packages/notifier-api/src/lib/get-auth-bearer.ts b/packages/notifier-api/src/lib/get-auth-bearer.ts new file mode 100644 index 00000000..2092de24 --- /dev/null +++ b/packages/notifier-api/src/lib/get-auth-bearer.ts @@ -0,0 +1,11 @@ +/** + * Get the token placed in the request header. + */ +export function getAuthBearer(authorizationHeader?: string): string | null { + const auth = authorizationHeader?.split(' '); + if (!auth || auth[0].toLowerCase() !== 'bearer' || !auth[1]) { + return null; + } + // else + return auth[1]; +} From a6353d6ef645f020cbc3e11f64b2ed85e8c19f4a Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Fri, 25 Oct 2024 21:58:09 +0330 Subject: [PATCH 10/13] refactor(config): cleanup --- packages/notifier-api/src/config.ts | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/packages/notifier-api/src/config.ts b/packages/notifier-api/src/config.ts index a7b4304c..32cf4b65 100644 --- a/packages/notifier-api/src/config.ts +++ b/packages/notifier-api/src/config.ts @@ -1,7 +1,7 @@ import {createLogger, packageTracer} from 'alwatr/nanolib'; import {Region, StoreFileType, type AlwatrNitrobaseConfig, type StoreFileStat} from 'alwatr/nitrobase'; -import type {NanotronApiServerConfig, HashGeneratorConfig} from 'alwatr/nanotron'; +import type {NanotronApiServerConfig} from 'alwatr/nanotron'; import type {PollingOptions, ApiClientOptions} from 'grammy'; __dev_mode__: packageTracer.add(__package_name__, __package_version__); @@ -11,16 +11,10 @@ export const logger = /* #__PURE__ */ createLogger(__package_name__); const env = /* #__PURE__ */ (() => { const devConfig = { dbPath: './db', - tokenSecret: 'DEV_SECRET', host: '0.0.0.0', port: 8000, botToken: 'BOT_TOKEN', - botUsername: 'BOT_USERNAME', - botFirstName: 'BOT_FIRST_NAME', - dropPendingUpdates: '1', - botAdminChatId: 'ADMIN_CHAT_ID', - adminToken: 'ADMIN_TOKEN', - + accessToken: 'ADMIN_TOKEN', } as const; const env_ = { @@ -37,7 +31,7 @@ const env = /* #__PURE__ */ (() => { })(); export const config = { - adminToken: env.adminToken!, + accessToken: env.accessToken!, nanotronApiServer: { host: env.host!, @@ -65,13 +59,6 @@ export const config = { allowed_updates: ['message'], } as PollingOptions, } as const, - - hashGenerator: { - algorithm: 'sha1', - crcLength: 3, - encoding: 'hex', - prefix: 'ca' // caTEGORY - } as HashGeneratorConfig, } as const; __dev_mode__: logger.logProperty?.('config', config); From f57a0eb622308e62329612793ced3f55901b5700 Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Fri, 25 Oct 2024 21:59:23 +0330 Subject: [PATCH 11/13] fix: review amd fix routes --- packages/notifier-api/src/route/new-category.ts | 9 +++++---- packages/notifier-api/src/route/notify.ts | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/notifier-api/src/route/new-category.ts b/packages/notifier-api/src/route/new-category.ts index 34f21895..cb33dc41 100644 --- a/packages/notifier-api/src/route/new-category.ts +++ b/packages/notifier-api/src/route/new-category.ts @@ -2,6 +2,7 @@ import {HttpStatusCodes, type NanotronClientRequest} from 'alwatr/nanotron'; import {logger} from '../config.js'; import {parseBodyAsJson} from '../handler/parse-body-as-json.js'; +import { requireAccessToken } from '../handler/require-access-token.js'; import {bot} from '../lib/bot.js'; import {openCategoryCollection} from '../lib/nitrobase.js'; import {nanotronApiServer} from '../lib/server.js'; @@ -14,7 +15,7 @@ export type NewCategoryOption = { nanotronApiServer.defineRoute<{body: NewCategoryOption}>({ method: 'POST', url: 'new-category', - preHandlers: [parseBodyAsJson, newCategoryValidation], + preHandlers: [requireAccessToken, parseBodyAsJson, newCategoryValidation], async handler() { logger.logMethod?.('newCategoryRoute'); @@ -41,7 +42,7 @@ export async function newCategoryValidation(this: NanotronClientRequest<{body: J if (title === undefined || typeof title !== 'string') { this.serverResponse.statusCode = HttpStatusCodes.Error_Client_400_Bad_Request; - this.serverResponse.replyJson({ + this.serverResponse.replyErrorResponse({ ok: false, errorCode: 'title_required', errorMessage: 'Title is required.', @@ -51,7 +52,7 @@ export async function newCategoryValidation(this: NanotronClientRequest<{body: J if (id === undefined || typeof id !== 'string') { this.serverResponse.statusCode = HttpStatusCodes.Error_Client_400_Bad_Request; - this.serverResponse.replyJson({ + this.serverResponse.replyErrorResponse({ ok: false, errorCode: 'id_required', errorMessage: 'Id is required.', @@ -63,7 +64,7 @@ export async function newCategoryValidation(this: NanotronClientRequest<{body: J if (categoryCollection.hasItem(id)) { this.serverResponse.statusCode = HttpStatusCodes.Error_Client_400_Bad_Request; - this.serverResponse.replyJson({ + this.serverResponse.replyErrorResponse({ ok: false, errorCode: 'category_exist', errorMessage: `Category ${id} already exist.`, diff --git a/packages/notifier-api/src/route/notify.ts b/packages/notifier-api/src/route/notify.ts index cd2688d7..a7939527 100644 --- a/packages/notifier-api/src/route/notify.ts +++ b/packages/notifier-api/src/route/notify.ts @@ -2,6 +2,7 @@ import {HttpStatusCodes, type NanotronClientRequest} from 'alwatr/nanotron'; import {logger} from '../config.js'; import {parseBodyAsJson} from '../handler/parse-body-as-json.js'; +import { requireAccessToken } from '../handler/require-access-token.js'; import { openCategoryCollection } from '../lib/nitrobase.js'; import {nanotronApiServer} from '../lib/server.js'; import {telegramNotify, type TelegramNotifyOption} from '../lib/telegram-notify.js'; @@ -9,7 +10,7 @@ import {telegramNotify, type TelegramNotifyOption} from '../lib/telegram-notify. nanotronApiServer.defineRoute<{body: TelegramNotifyOption}>({ method: 'POST', url: 'notify', - preHandlers: [parseBodyAsJson, notifyValidation], + preHandlers: [requireAccessToken, parseBodyAsJson, notifyValidation], async handler() { logger.logMethod?.('notifyRoute'); @@ -29,7 +30,7 @@ export async function notifyValidation(this: NanotronClientRequest<{body: JsonOb if (categoryId === undefined || typeof categoryId !== 'string') { this.serverResponse.statusCode = HttpStatusCodes.Error_Client_400_Bad_Request; - this.serverResponse.replyJson({ + this.serverResponse.replyErrorResponse({ ok: false, errorCode: 'category_required', errorMessage: 'Category is required.', @@ -39,7 +40,7 @@ export async function notifyValidation(this: NanotronClientRequest<{body: JsonOb if (message === undefined || typeof message !== 'string') { this.serverResponse.statusCode = HttpStatusCodes.Error_Client_400_Bad_Request; - this.serverResponse.replyJson({ + this.serverResponse.replyErrorResponse({ ok: false, errorCode: 'message_required', errorMessage: 'Message is required.', @@ -51,7 +52,7 @@ export async function notifyValidation(this: NanotronClientRequest<{body: JsonOb if (categoryCollection.hasItem(categoryId) === false) { this.serverResponse.statusCode = HttpStatusCodes.Error_Client_400_Bad_Request; - this.serverResponse.replyJson({ + this.serverResponse.replyErrorResponse({ ok: false, errorCode: 'category_not_found', errorMessage: `Category ${categoryId} not found.`, From c59925d05f00d7c51c3c840a0f580d41c7ba232f Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Fri, 25 Oct 2024 22:14:09 +0330 Subject: [PATCH 12/13] chore: cleanup --- packages/notifier-api/src/lib/hash.ts | 5 -- tsconfig.base.json | 76 --------------------------- tsconfig.json | 13 ----- 3 files changed, 94 deletions(-) delete mode 100644 packages/notifier-api/src/lib/hash.ts delete mode 100644 tsconfig.base.json delete mode 100644 tsconfig.json diff --git a/packages/notifier-api/src/lib/hash.ts b/packages/notifier-api/src/lib/hash.ts deleted file mode 100644 index 5d149d55..00000000 --- a/packages/notifier-api/src/lib/hash.ts +++ /dev/null @@ -1,5 +0,0 @@ -import {AlwatrHashGenerator} from 'alwatr/nanotron'; - -import {config} from '../config.js'; - -export const hashGenerator = new AlwatrHashGenerator(config.hashGenerator); diff --git a/tsconfig.base.json b/tsconfig.base.json deleted file mode 100644 index 32692253..00000000 --- a/tsconfig.base.json +++ /dev/null @@ -1,76 +0,0 @@ -// https://www.typescriptlang.org/tsconfig - -{ - "compilerOptions": { - /* Basic Options */ - "incremental": true, - "target": "ES2020", - "module": "NodeNext", - "moduleResolution": "NodeNext", - "resolveJsonModule": true, // temporary for fix import json issue - "lib": ["ES2023", "DOM", "DOM.Iterable"], - // "allowJs": true, - // "checkJs": true, - // "jsx": "preserve", - "declaration": true, - "declarationMap": true, - // "outFile": "./", - "outDir": "./", - // "rootDir": "./src", - "composite": true, - "tsBuildInfoFile": ".tsbuildinfo", - "removeComments": false, - // "noEmit": true, - "importHelpers": true, - // "downlevelIteration": true, - "isolatedModules": true, // need for esbuild - - /* Strict Type-Checking Options */ - "strict": true, - "noImplicitAny": true, - "strictNullChecks": true, - "strictFunctionTypes": true, - "strictBindCallApply": true, - "strictPropertyInitialization": true, - "noImplicitThis": true, - "alwaysStrict": true, - - /* Additional Checks */ - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "noImplicitOverride": true, - // "noUncheckedIndexedAccess": true, - // "noPropertyAccessFromIndexSignature": true, - - /* Module Resolution Options */ - // "paths": {}, - // "rootDirs": [], - // "typeRoots": [], - // "types": [], - "allowSyntheticDefaultImports": true, - // "esModuleInterop": true, - // "preserveSymlinks": true, - // "allowUmdGlobalAccess": true, - - /* Source Map Options */ - "sourceMap": true, - // "sourceRoot": "", - // "mapRoot": "", - // "inlineSourceMap": true, - "inlineSources": true, - - /* Experimental Options */ - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - - /* Advanced Options */ - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "useDefineForClassFields": false, - - "listEmittedFiles": true - // "diagnostics": true, - } -} diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 6b10e161..00000000 --- a/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -// https://www.typescriptlang.org/tsconfig - -{ - "extends": "./tsconfig.base", - "compilerOptions": { - "composite": true, - "tsBuildInfoFile": ".tsbuildinfo", - "plugins": [] - }, - "files": [], - "exclude": [], - "references": [{"path": "./packages/telegram"}] -} From 434ea0f704178554159ec6c00698db1fce5081f8 Mon Sep 17 00:00:00 2001 From: Ali Mihandoost Date: Fri, 25 Oct 2024 22:14:55 +0330 Subject: [PATCH 13/13] style: make lint happy --- packages/notifier-api/src/command/start-command.ts | 8 +++----- packages/notifier-api/src/handler/parse-body-as-json.ts | 4 +--- packages/notifier-api/src/handler/require-access-token.ts | 4 ++-- packages/notifier-api/src/lib/escape-message.ts | 2 +- packages/notifier-api/src/lib/get-auth-bearer.ts | 4 ++-- packages/notifier-api/src/lib/telegram-notify.ts | 2 +- packages/notifier-api/src/route/new-category.ts | 2 +- packages/notifier-api/src/route/notify.ts | 4 ++-- 8 files changed, 13 insertions(+), 17 deletions(-) diff --git a/packages/notifier-api/src/command/start-command.ts b/packages/notifier-api/src/command/start-command.ts index a443e0cd..45474e59 100644 --- a/packages/notifier-api/src/command/start-command.ts +++ b/packages/notifier-api/src/command/start-command.ts @@ -1,9 +1,7 @@ -import {config, logger} from '../config.js'; +import {logger} from '../config.js'; import {bot} from '../lib/bot.js'; import {message} from '../lib/message.js'; -import {openCategoryCollection, nitrobase} from '../lib/nitrobase.js'; - -import type {Category} from '../type.js'; +import {openCategoryCollection} from '../lib/nitrobase.js'; bot.command( 'start', @@ -65,5 +63,5 @@ bot.command( catch (error) { logger.error?.('startCommand', 'unexpected_error', error, {categoryId, from: ctx.from, chat: ctx.chat}); } - } + }, ); diff --git a/packages/notifier-api/src/handler/parse-body-as-json.ts b/packages/notifier-api/src/handler/parse-body-as-json.ts index 89ad0601..7143daeb 100644 --- a/packages/notifier-api/src/handler/parse-body-as-json.ts +++ b/packages/notifier-api/src/handler/parse-body-as-json.ts @@ -4,9 +4,7 @@ import {logger} from '../config.js'; import type {NanotronClientRequest} from 'alwatr/nanotron'; -export async function parseBodyAsJson( - this: NanotronClientRequest<{body?: JsonObject}>, -): Promise { +export async function parseBodyAsJson(this: NanotronClientRequest<{body?: JsonObject}>): Promise { const bodyBuffer = await this.getBodyRaw(); if (bodyBuffer.length === 0) { logger.error('parseBodyAsJson', 'body_required'); diff --git a/packages/notifier-api/src/handler/require-access-token.ts b/packages/notifier-api/src/handler/require-access-token.ts index 51a1a81e..4d30448f 100644 --- a/packages/notifier-api/src/handler/require-access-token.ts +++ b/packages/notifier-api/src/handler/require-access-token.ts @@ -1,7 +1,7 @@ import {HttpStatusCodes, type NanotronClientRequest} from 'alwatr/nanotron'; import {config, logger} from '../config.js'; -import { getAuthBearer } from '../lib/get-auth-bearer.js'; +import {getAuthBearer} from '../lib/get-auth-bearer.js'; export async function requireAccessToken(this: NanotronClientRequest): Promise { const token = getAuthBearer(this.headers.authorization); @@ -12,7 +12,7 @@ export async function requireAccessToken(this: NanotronClientRequest): Promise', '#', '+', '-', '=', '|', '{', '}', '.', '!']; -const scapeCharsRegex = new RegExp(`[${scapeChars.map(char => `\\${char}`).join('')}]`, 'g'); +const scapeCharsRegex = new RegExp(`[${scapeChars.map((char) => `\\${char}`).join('')}]`, 'g'); export function escapeMessage(message: string): string { return message.replace(scapeCharsRegex, '\\$&'); diff --git a/packages/notifier-api/src/lib/get-auth-bearer.ts b/packages/notifier-api/src/lib/get-auth-bearer.ts index 2092de24..78661808 100644 --- a/packages/notifier-api/src/lib/get-auth-bearer.ts +++ b/packages/notifier-api/src/lib/get-auth-bearer.ts @@ -1,6 +1,6 @@ /** - * Get the token placed in the request header. - */ + * Get the token placed in the request header. + */ export function getAuthBearer(authorizationHeader?: string): string | null { const auth = authorizationHeader?.split(' '); if (!auth || auth[0].toLowerCase() !== 'bearer' || !auth[1]) { diff --git a/packages/notifier-api/src/lib/telegram-notify.ts b/packages/notifier-api/src/lib/telegram-notify.ts index 6c9fab25..e0d45554 100644 --- a/packages/notifier-api/src/lib/telegram-notify.ts +++ b/packages/notifier-api/src/lib/telegram-notify.ts @@ -8,7 +8,7 @@ export type TelegramNotifyOption = { categoryId: string; message: string; markdown: boolean; -} +}; /** * Send a message to all members of the `categoryId`. diff --git a/packages/notifier-api/src/route/new-category.ts b/packages/notifier-api/src/route/new-category.ts index cb33dc41..bb20a752 100644 --- a/packages/notifier-api/src/route/new-category.ts +++ b/packages/notifier-api/src/route/new-category.ts @@ -2,7 +2,7 @@ import {HttpStatusCodes, type NanotronClientRequest} from 'alwatr/nanotron'; import {logger} from '../config.js'; import {parseBodyAsJson} from '../handler/parse-body-as-json.js'; -import { requireAccessToken } from '../handler/require-access-token.js'; +import {requireAccessToken} from '../handler/require-access-token.js'; import {bot} from '../lib/bot.js'; import {openCategoryCollection} from '../lib/nitrobase.js'; import {nanotronApiServer} from '../lib/server.js'; diff --git a/packages/notifier-api/src/route/notify.ts b/packages/notifier-api/src/route/notify.ts index a7939527..c1c71475 100644 --- a/packages/notifier-api/src/route/notify.ts +++ b/packages/notifier-api/src/route/notify.ts @@ -2,8 +2,8 @@ import {HttpStatusCodes, type NanotronClientRequest} from 'alwatr/nanotron'; import {logger} from '../config.js'; import {parseBodyAsJson} from '../handler/parse-body-as-json.js'; -import { requireAccessToken } from '../handler/require-access-token.js'; -import { openCategoryCollection } from '../lib/nitrobase.js'; +import {requireAccessToken} from '../handler/require-access-token.js'; +import {openCategoryCollection} from '../lib/nitrobase.js'; import {nanotronApiServer} from '../lib/server.js'; import {telegramNotify, type TelegramNotifyOption} from '../lib/telegram-notify.js';