Skip to content

Commit

Permalink
feat(telegram): implement telegram notifier
Browse files Browse the repository at this point in the history
  • Loading branch information
async3619 committed Dec 11, 2022
1 parent 5b97115 commit 703d676
Show file tree
Hide file tree
Showing 21 changed files with 376 additions and 104 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,14 @@ notifier configuration for Discord WebHook notifier.
"webhookUrl": "Discord WebHook url" // string, required
}
```

#### telegram

notifier configuration for Telegram Bot notifier.

```json5
{
"type": "telegram",
"botToken": "token that generated from https://t.me/CageNotifierBot" // string, required
}
```
23 changes: 22 additions & 1 deletion config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,35 @@
"webhookUrl"
],
"additionalProperties": false
},
"telegram": {
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "telegram"
},
"token": {
"type": "string"
},
"url": {
"type": "string"
}
},
"required": [
"token",
"type"
],
"additionalProperties": false
}
},
"additionalProperties": false
}
},
"required": [
"watchInterval",
"watchers"
"watchers",
"notifiers"
],
"additionalProperties": false
}
Expand Down
13 changes: 3 additions & 10 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,18 +97,11 @@ export class App extends Loggable {
});
}

for (const notifier of notifiers) {
const options = this.config.notifierOptions?.[notifier.getName().toLowerCase()];
if (!options) {
this.logger.warn(`no options are configured for \`${chalk.green("{}")}\` notifier. skipping...`, [
notifier.getName(),
]);
}

for (const [, notifier] of notifiers) {
await this.logger.work({
level: "info",
message: `initialize \`${chalk.green(notifier.getName())}\` notifier`,
work: () => notifier.initialize(options),
work: () => notifier.initialize(),
});
}

Expand Down Expand Up @@ -246,7 +239,7 @@ export class App extends Loggable {
}

const watcherMap = this.config.watcherMap;
for (const notifier of notifiers) {
for (const [, notifier] of notifiers) {
await notifier.notify(
newLogs.map(log => {
return [watcherMap[log.user.from], log];
Expand Down
35 changes: 27 additions & 8 deletions src/notifiers/base.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,40 @@
import { UserLog } from "@repositories/models/user-log";

import { BaseWatcher } from "@watchers/base";
import { NotifyPair } from "@notifiers/type";

import { Loggable } from "@utils/types";
import { UserLogType } from "@repositories/models/user-log";
import { Logger } from "@utils/logger";

export type NotifyPair = [BaseWatcher<string>, UserLog];

export abstract class BaseNotifier extends Loggable {
protected constructor(name: string) {
export abstract class BaseNotifier<TType extends string> extends Loggable<TType> {
protected constructor(name: TType) {
super(name);
}

public getName() {
return super.getName().replace("Notifier", "");
}

public abstract initialize(options: Record<string, any>): Promise<void>;
public abstract initialize(): Promise<void>;

public abstract notify(logs: NotifyPair[]): Promise<void>;

protected formatNotify(pair: NotifyPair): string {
const [watcher, log] = pair;
const { user } = log;

if (log.type === UserLogType.RenameUserId || log.type === UserLogType.RenameDisplayName) {
const tokens = [
watcher.getName(),
log.oldDisplayName || "",
log.oldUserId || "",
watcher.getProfileUrl(log.user),
log.type === UserLogType.RenameDisplayName ? "" : "@",
log.type === UserLogType.RenameUserId ? user.userId : user.displayName,
];

return Logger.format("[{}] [{} (@{})]({}) → {}{}", ...tokens);
}

const tokens = [watcher.getName(), user.displayName, user.userId, watcher.getProfileUrl(user)];
return Logger.format("[{}] [{} (@{})]({})", ...tokens);
}
}
49 changes: 10 additions & 39 deletions src/notifiers/discord.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import pluralize from "pluralize";
import dayjs from "dayjs";

import { User } from "@repositories/models/user";
import { UserLog, UserLogType } from "@repositories/models/user-log";
import { UserLogType } from "@repositories/models/user-log";

import { BaseNotifier, NotifyPair } from "@notifiers/base";
import { BaseWatcher } from "@watchers/base";
import { BaseNotifier } from "@notifiers/base";
import { BaseNotifierOption, NotifyPair } from "@notifiers/type";

import { Fetcher } from "@utils/fetcher";
import { Logger } from "@utils/logger";

export interface DiscordNotifierOptions {
type: "discord";
export interface DiscordNotifierOptions extends BaseNotifierOption<DiscordNotifier> {
webhookUrl: string;
}

interface DiscordWebhookData {
content: any;
embeds: {
Expand All @@ -32,18 +29,17 @@ interface DiscordWebhookData {
attachments: [];
}

export class DiscordNotifier extends BaseNotifier {
export class DiscordNotifier extends BaseNotifier<"Discord"> {
private readonly fetcher = new Fetcher();
private webhookUrl: string | null = null;

public constructor() {
super(DiscordNotifier.name);
public constructor(private readonly options: DiscordNotifierOptions) {
super("Discord");
}

public async initialize(options: DiscordNotifierOptions) {
this.webhookUrl = options.webhookUrl;
public async initialize() {
this.webhookUrl = this.options.webhookUrl;
}

public async notify(pairs: NotifyPair[]) {
if (!this.webhookUrl) {
throw new Error("DiscordNotifier is not initialized");
Expand Down Expand Up @@ -123,35 +119,10 @@ export class DiscordNotifier extends BaseNotifier {
value: valueLines.join("\n"),
};
}

private generateEmbedField(logs: NotifyPair[], title: string) {
return {
name: title,
value: logs
.map<[BaseWatcher<string>, User, UserLog]>(([w, l]) => [w, l.user, l])
.slice(0, 10)
.map(([watcher, user, log]) => {
if (log.type === UserLogType.RenameUserId || log.type === UserLogType.RenameDisplayName) {
return Logger.format(
"[{}] [{} (@{})]({}) → {}{}",
watcher.getName(),
log.oldDisplayName,
log.oldUserId,
watcher.getProfileUrl(log.user),
log.type === UserLogType.RenameDisplayName ? "" : "@",
log.type === UserLogType.RenameUserId ? user.userId : user.displayName,
);
}

return Logger.format(
"[{}] [{} (@{})]({})",
watcher.getName(),
user.displayName,
user.userId,
watcher.getProfileUrl(user),
);
})
.join("\n"),
value: logs.slice(0, 10).map(this.formatNotify).join("\n"),
};
}
}
29 changes: 27 additions & 2 deletions src/notifiers/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,33 @@
import { BaseNotifier } from "@notifiers/base";
import { DiscordNotifier, DiscordNotifierOptions } from "@notifiers/discord";
import { TelegramNotifier, TelegramNotifierOptions } from "@notifiers/telegram";
import { BaseNotifierOption } from "@notifiers/type";

import { TypeMap } from "@utils/types";

export type NotifierOptions = DiscordNotifierOptions;
export type NotifierClasses = DiscordNotifier | TelegramNotifier;
export type NotifierTypes = Lowercase<NotifierClasses["name"]>;

export type NotifierOptions = DiscordNotifierOptions | TelegramNotifierOptions;
export type NotifierOptionMap = TypeMap<NotifierOptions>;

export const AVAILABLE_NOTIFIERS: ReadonlyArray<BaseNotifier> = [new DiscordNotifier()];
export type NotifierMap = {
[TKey in NotifierTypes]: TKey extends NotifierTypes ? Extract<NotifierClasses, { name: TKey }> : never;
};
export type NotifierFactoryMap = {
[TKey in NotifierTypes]: TKey extends NotifierTypes
? (options: NotifierOptionMap[TKey]) => Extract<NotifierClasses, { name: Capitalize<TKey> }>
: never;
};
export type NotifierPair = [NotifierTypes, BaseNotifier<string>];

const AVAILABLE_NOTIFIERS: Readonly<NotifierFactoryMap> = {
discord: options => new DiscordNotifier(options),
telegram: options => new TelegramNotifier(options),
};

export const createNotifier = (options: BaseNotifierOption): BaseNotifier<string> => {
const { type } = options;

return AVAILABLE_NOTIFIERS[type](options);
};
23 changes: 23 additions & 0 deletions src/notifiers/telegram/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export const TELEGRAM_FOLLOWERS_TEMPLATE = `
*🎉 {} new {}*
{}
{}
`.trim();

export const TELEGRAM_UNFOLLOWERS_TEMPLATE = `
*❌ {} {}*
{}
{}
`.trim();

export const TELEGRAM_RENAMES_TEMPLATE = `
*✏️ {} {}*
{}
{}
`.trim();

export const TELEGRAM_LOG_COUNT = 25;
export const FORBIDDEN_CHARACTERS = "()._-`*".split("");
Loading

0 comments on commit 703d676

Please sign in to comment.