├── .gitignore ├── .env.sample ├── src ├── database │ ├── sessionsDb.ts │ ├── connect.ts │ ├── usersDb.ts │ └── welcomeDb.ts ├── core │ ├── i18n.ts │ ├── interfaces.ts │ └── types.ts ├── helpers │ ├── baseHelpers.ts │ ├── permChecker.ts │ ├── functions.ts │ └── conversationHelpers.ts └── modules │ ├── mod.ts │ ├── langSettings.ts │ ├── start.ts │ ├── chatJoins.ts │ ├── help.ts │ ├── chatSettings.ts │ └── ownerTools.ts ├── .vscode └── settings.json ├── deno.json ├── env.ts ├── .github └── workflows │ └── tgnotifs.yml ├── import_map.json ├── locales ├── cn.ftl ├── kr.ftl ├── ja.ftl ├── ar.ftl ├── en.ftl ├── or.ftl ├── bn.ftl ├── tr.ftl ├── gu.ftl ├── pn.ftl ├── as.ftl ├── mr.ftl ├── hi.ftl ├── ne.ftl ├── da.ftl ├── id.ftl ├── es.ftl ├── kn.ftl ├── ta.ftl ├── te.ftl ├── ru.ftl ├── ml.ftl ├── it.ftl ├── de.ftl └── fr.ftl ├── install.sh ├── README.md ├── main.ts └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | *.test.ts 3 | deno.lock -------------------------------------------------------------------------------- /.env.sample: -------------------------------------------------------------------------------- 1 | BOT_TOKEN= 2 | OWNERS= 3 | MONGO_URL= -------------------------------------------------------------------------------- /src/database/sessionsDb.ts: -------------------------------------------------------------------------------- 1 | import { db } from "./connect.ts"; 2 | 3 | import { ISession } from "mongo_sessions"; 4 | 5 | export const sessionsCollection = db.collection( 6 | "sessions", 7 | ); 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deno.enable": true, 3 | "deno.unstable": true, 4 | "editor.defaultFormatter": "denoland.vscode-deno", 5 | "[markdown]": { 6 | "editor.defaultFormatter": "esbenp.prettier-vscode" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/core/i18n.ts: -------------------------------------------------------------------------------- 1 | import { MyContext } from "./types.ts"; 2 | 3 | import { I18n } from "i18n"; 4 | 5 | const i18n = new I18n({ 6 | defaultLocale: "en", 7 | useSession: true, 8 | }); 9 | 10 | export default i18n; 11 | -------------------------------------------------------------------------------- /deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "importMap": "./import_map.json", 3 | "tasks": { 4 | "poll": "deno run --allow-net --allow-read --allow-env main.ts --polling", 5 | "webhook": "deno run --allow-net --allow-read --allow-env main.ts" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /env.ts: -------------------------------------------------------------------------------- 1 | import { config } from "dotenv"; 2 | import { cleanEnv, str } from "envalid"; 3 | 4 | await config({ export: true }); 5 | 6 | export default cleanEnv(Deno.env.toObject(), { 7 | BOT_TOKEN: str(), 8 | OWNERS: str(), 9 | MONGO_URL: str(), 10 | }); 11 | -------------------------------------------------------------------------------- /src/helpers/baseHelpers.ts: -------------------------------------------------------------------------------- 1 | import config from "$env"; 2 | 3 | const owners: number[] = []; 4 | for (const owner of config.OWNERS.split(" ")) { 5 | owners.push(Number(owner)); 6 | } 7 | 8 | class Helpers { 9 | OWNERS = owners; 10 | TOTAL_USERS_SEEN = 0; 11 | START_TIME = new Date().valueOf(); 12 | } 13 | 14 | export default new Helpers(); 15 | -------------------------------------------------------------------------------- /src/core/interfaces.ts: -------------------------------------------------------------------------------- 1 | import { ObjectId } from "mongo"; 2 | 3 | export interface UserSchema { 4 | _id: ObjectId; 5 | userID: number; 6 | } 7 | 8 | export interface SettingsSchema { 9 | _id: ObjectId; 10 | chatID: number; 11 | status: boolean; 12 | welcome: string; 13 | } 14 | 15 | export interface SessionData { 16 | __language_code?: string; 17 | } 18 | -------------------------------------------------------------------------------- /src/core/types.ts: -------------------------------------------------------------------------------- 1 | import { SessionData } from "./interfaces.ts"; 2 | 3 | import { Context, SessionFlavor } from "grammy/mod.ts"; 4 | import { HydrateFlavor } from "hydrate"; 5 | import { type Conversation, type ConversationFlavor } from "conversations"; 6 | import { I18nFlavor } from "i18n"; 7 | 8 | export type MyContext = HydrateFlavor< 9 | Context & SessionFlavor & I18nFlavor & ConversationFlavor 10 | >; 11 | 12 | export type MyConversation = Conversation; 13 | -------------------------------------------------------------------------------- /src/helpers/permChecker.ts: -------------------------------------------------------------------------------- 1 | import { MyContext } from "../core/types.ts"; 2 | 3 | export async function get_perms( 4 | ctx: MyContext, 5 | chat: number, 6 | user: number, 7 | ) { 8 | try { 9 | const stats = await ctx.api.getChatMember(chat, user); 10 | if (stats.status == "administrator" || stats.status == "creator") { 11 | return true; 12 | } else return false; 13 | } catch (error) { 14 | if (error.error_code == 400) return null; 15 | console.error(error); 16 | return null; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/database/connect.ts: -------------------------------------------------------------------------------- 1 | import config from "$env"; 2 | import { MongoClient } from "mongo"; 3 | 4 | console.log("Connecting to MongoDB..."); 5 | const client = new MongoClient(); 6 | let MONGO_URL = config.MONGO_URL; 7 | if (!MONGO_URL.endsWith("authMechanism=SCRAM-SHA-1")) { 8 | MONGO_URL += "&authMechanism=SCRAM-SHA-1"; 9 | } 10 | try { 11 | await client.connect(MONGO_URL); 12 | } catch (err) { 13 | console.error("Error connecting to MongoDB", err); 14 | throw err; 15 | } 16 | 17 | export const db = client.database("ChannelActions"); 18 | -------------------------------------------------------------------------------- /src/modules/mod.ts: -------------------------------------------------------------------------------- 1 | import { MyContext } from "../core/types.ts"; 2 | import start from "./start.ts"; 3 | import help from "./help.ts"; 4 | import chatSettings from "./chatSettings.ts"; 5 | import langSettings from "./langSettings.ts"; 6 | import chatJoins from "./chatJoins.ts"; 7 | import ownerTools from "./ownerTools.ts"; 8 | 9 | import { Composer } from "grammy/mod.ts"; 10 | 11 | const composer = new Composer(); 12 | 13 | composer.use( 14 | start, 15 | help, 16 | chatSettings, 17 | langSettings, 18 | chatJoins, 19 | ownerTools, 20 | ); 21 | 22 | export default composer; 23 | -------------------------------------------------------------------------------- /.github/workflows/tgnotifs.yml: -------------------------------------------------------------------------------- 1 | name: Telegram Notifications 2 | on: 3 | push: 4 | workflow_dispatch: 5 | issues: 6 | types: [opened, edited, deleted, reopened, locked, unlocked] 7 | issue_comment: 8 | types: [created, deleted] 9 | pull_request: 10 | types: [opened, reopened, closed, locked, unlocked] 11 | jobs: 12 | notify: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Telegram Notifications for Actions on GitHub 17 | uses: EverythingSuckz/github-telegram-notify@main 18 | with: 19 | bot_token: '${{ secrets.BOT_TOKEN }}' 20 | chat_id: '${{ secrets.CHAT_ID }}' 21 | -------------------------------------------------------------------------------- /src/helpers/functions.ts: -------------------------------------------------------------------------------- 1 | import i18n from "../core/i18n.ts"; 2 | 3 | import { InlineKeyboard } from "grammy/mod.ts"; 4 | import { getLanguageInfo } from "language"; 5 | 6 | export function getAvaialableLocalesButtons(currentLocale: string) { 7 | const keyboard = new InlineKeyboard(); 8 | let c = 1; 9 | for (const locale of i18n.locales) { 10 | let localName = getLanguageInfo(locale)?.nativeName ?? locale; 11 | if (locale === currentLocale) { 12 | localName += " ✅"; 13 | } 14 | keyboard.text(localName, `setlang_${locale}`); 15 | c += 1; 16 | if (c == 2) { 17 | keyboard.row(); 18 | c = 0; 19 | } 20 | } 21 | return keyboard.row().text("« Back", "mainMenu"); 22 | } 23 | -------------------------------------------------------------------------------- /import_map.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": { 3 | "dotenv": "https://deno.land/std@0.154.0/dotenv/mod.ts", 4 | "envalid": "https://deno.land/x/envalid@0.1.2/mod.ts", 5 | "server": "https://deno.land/std@0.154.0/http/server.ts", 6 | "grammy/": "https://deno.land/x/grammy@v1.19.0/", 7 | "mongo": "https://deno.land/x/mongo@v0.31.1/mod.ts", 8 | "autoQuote": "https://deno.land/x/grammy_autoquote@v1.1.2/mod.ts", 9 | "hydrate": "https://deno.land/x/grammy_hydrate@v1.3.1/mod.ts", 10 | "conversations": "https://deno.land/x/grammy_conversations@v1.1.2/mod.ts", 11 | "i18n": "https://deno.land/x/grammy_i18n@v1.0.1/mod.ts", 12 | "mongo_sessions": "https://deno.land/x/grammy_storages@v2.1.0/mongodb/src/mod.ts", 13 | "language": "https://deno.land/x/language@v0.1.0/mod.ts", 14 | "grammy_runner": "https://deno.land/x/grammy_runner@v1.0.4/mod.ts", 15 | "$env": "./env.ts" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/database/usersDb.ts: -------------------------------------------------------------------------------- 1 | import { db } from "./connect.ts"; 2 | import { UserSchema } from "../core/interfaces.ts"; 3 | 4 | export const users = db.collection("BOTUSERS"); 5 | 6 | export async function addUser(userId: number) { 7 | const user = await users.findOne({ userID: userId }); 8 | if (user) return; 9 | await users.insertOne({ userID: userId }); 10 | } 11 | 12 | export async function removeUser(userId: number) { 13 | const user = await users.findOne({ userID: userId }); 14 | if (!user) return; 15 | await users.deleteOne({ userID: userId }); 16 | } 17 | 18 | export async function countUsers() { 19 | const count = await users.countDocuments({ userID: { $ne: 0 } }); 20 | return count; 21 | } 22 | 23 | export async function addAll(usrs: number[]) { 24 | const a = []; 25 | for (const user of usrs) { 26 | a.push({ userID: user }); 27 | } 28 | await users.insertMany(a); 29 | } 30 | -------------------------------------------------------------------------------- /locales/cn.ftl: -------------------------------------------------------------------------------- 1 | start-msg = 你好 {$user}! 2 | 我是频道操作机器人, 一个机器人主要专注于使用新的 管理员批准邀请链接. 3 | 4 | 我可以: 5 | - 自动批准新的加入请求 6 | - 自动拒绝新加入请求 7 | 8 | 单击下面的按钮以了解如何使用我! 9 | 10 | help = 使用说明 11 | 12 | 以管理员身份将我添加到您的频道,并拥有“添加用户”权限,然后将聊天中的消息转发给我以进行设置! 13 | 14 | usage-help = 如何使用我 ❓ 15 | 16 | updates = 更新 17 | 18 | no-perms = 我没有以管理员身份添加到聊天中,或者您不是聊天中的管理员! 19 | 20 | not-admin = 您不是聊天中的管理员! 21 | 22 | btn-approve = 批准新成员 23 | 24 | btn-disapprove = 不批准新成员 25 | 26 | btn-custom = 自定义欢迎信息 27 | 28 | chat-settings = *设置 {$title}* 29 | 30 | 当前的设置: 31 | AutoApprove: {$autoappr}. 32 | 33 | chat-settings-approved = 设置更新!频道中 {$title} 的新加入请求将被自动批准! 34 | 35 | chat-settings-disapproved = 设置更新!频道 {$title} 中的新加入请求将被自动拒绝! 36 | 37 | welcome-text = 输入您希望新批准/未批准成员收到的欢迎消息。 38 | 39 | 可用的格式: 40 | - $name - 用户名. 41 | - $chat - 聊天标题. 42 | 43 | provide-msg = 請提供信息! 44 | 45 | welcome-set = 欢迎留言设置为: 46 | {$msg} -------------------------------------------------------------------------------- /src/helpers/conversationHelpers.ts: -------------------------------------------------------------------------------- 1 | import { MyContext, MyConversation } from "../core/types.ts"; 2 | import { setWelcome } from "../database/welcomeDb.ts"; 3 | 4 | import { InlineKeyboard } from "grammy/mod.ts"; 5 | 6 | export async function inputWelcomeMsg( 7 | conversation: MyConversation, 8 | ctx: MyContext, 9 | ) { 10 | const chatID = ctx.match?.[1]; 11 | if (chatID == undefined) return; 12 | await ctx.editMessageText( 13 | ctx.t("welcome-text"), 14 | ); 15 | const { message } = await conversation.waitFor("message:text"); 16 | if (!message.text) { 17 | return await ctx.reply(ctx.t("provide-msg"), { 18 | reply_markup: new InlineKeyboard().text( 19 | "« Back", 20 | `settings_page_${chatID}`, 21 | ), 22 | }); 23 | } 24 | await setWelcome(Number(chatID), message.text); 25 | await ctx.reply(ctx.t("welcome-set", { msg: message.text }), { 26 | reply_markup: new InlineKeyboard().text( 27 | "Back", 28 | `settings_page_${chatID}`, 29 | ), 30 | }); 31 | } 32 | -------------------------------------------------------------------------------- /locales/kr.ftl: -------------------------------------------------------------------------------- 1 | start-msg = Hi {$user}! 2 | 나는 채널 작업 봇입니다, 주로 새로운 작업에 중점을 둔 봇관리자 승인 초대 링크. 3 | 4 | 저 할 수 있어요: 5 | - 새 가입 요청 자동 승인 6 | - 새 가입 요청을 자동으로 거부합니다. 7 | 8 | 나를 사용하는 방법을 알고 아래 버튼을 클릭! 9 | 10 | help = 사용 지침. 11 | 12 | 사용자 추가" 권한이 있는 관리자로 저를 채널에 추가하고 해당 채팅에서 메시지를 전달하여 저를 설정하세요! 13 | 14 | usage-help = 나를 사용하는 방법 ❓ 15 | 16 | updates = 업데이트 17 | 18 | no-perms = 채팅에 관리자로 추가되지 않았거나 채팅에 관리자가 아니었습니다! 19 | 20 | not-admin = 당신은 채팅의 관리자가 아닙니다! 21 | 22 | btn-approve = 신규 회원 승인 23 | 24 | btn-disapprove = 신규 회원 비승인 25 | 26 | btn-custom = 맞춤 환영 메시지 27 | 28 | chat-settings = *설정 {$title}* 29 | 30 | Current settings: 31 | AutoApprove: {$autoappr}. 32 | 33 | chat-settings-approved = 설정이 업데이트되었습니다! 채널의 새로운 가입 요청 {$title} 자동으로 승인됩니다! 34 | 35 | chat-settings-disapproved = 설정이 업데이트되었습니다! 채널의 새로운 가입 요청 {$title} 자동으로 비승인됩니다! 36 | 37 | welcome-text = 신규 승인/비승인 회원이 받을 환영 메시지를 입력합니다. 38 | 39 | Available formattings: 40 | - $name - 사용자 이름. 41 | - $chat - 채팅 제목. 42 | 43 | provide-msg = 메시지를 보내주세요! 44 | 45 | welcome-set = 환영 메시지가 다음으로 설정됨: 46 | {$msg} 47 | -------------------------------------------------------------------------------- /locales/ja.ftl: -------------------------------------------------------------------------------- 1 | start-msg = Hi {$user}! 2 | 私はチャンネルアクションボットです, 主に新しいものでの作業に焦点を当てたボット 管理者承認の招待リンク. 3 | 4 | できます: 5 | - 新しい参加リクエストを自動承認 6 | - 新しい参加リクエストの自動拒否. 7 | 8 | 下のボタンをクリックして、の使用方法を確認してください 私を ! 9 | 10 | help = 使用説明書. 11 | 12 | 「ユーザーの追加」権限を使用して、私を管理者としてチャンネルに追加し、そのチャットからメッセージを転送してセットアップしてください! 13 | 14 | usage-help = の使い方私を ❓ 15 | 16 | updates = アップデート 17 | 18 | no-perms = 私が管理者としてチャットに追加されていないか、あなたがチャットの管理者ではありません! 19 | 20 | not-admin = あなたはチャットの管理者ではありません! 21 | 22 | btn-approve = 新しいメンバーを承認する 23 | 24 | btn-disapprove = 新しいメンバーを不承認 25 | 26 | btn-custom = カスタム ウェルカム メッセージ 27 | 28 | chat-settings = *{$title}設定為に* 29 | 30 | 現在設定: 31 | 承認する自動: {$autoappr}. 32 | 33 | chat-settings-approved = 設定が更新されました!チャンネルでの新しい参加リクエスト {$title} になります自動承認! 34 | 35 | chat-settings-disapproved = 設定が更新されました!チャンネルでの新しい参加リクエスト {$title} になります自動的に不承認! 36 | 37 | welcome-text = 新しい承認/非承認メンバーに送信するウェルカム メッセージを入力します. 38 | 39 | 利用可能 フォーマット: 40 | - $name - ユーザー名. 41 | - $chat - チャットのタイトル. 42 | 43 | provide-msg = どうか メッセージを提供する! 44 | 45 | welcome-set = までウェルカム メッセージ セット: 46 | {$msg} 47 | -------------------------------------------------------------------------------- /src/database/welcomeDb.ts: -------------------------------------------------------------------------------- 1 | import { db } from "./connect.ts"; 2 | import { SettingsSchema } from "../core/interfaces.ts"; 3 | 4 | const settings = db.collection("CHAT_SETTINGS"); 5 | 6 | export async function setWelcome(chatID: number, welcome: string) { 7 | const chat = await settings.findOne({ chatID: chatID }); 8 | if (!chat) { 9 | await settings.insertOne({ 10 | chatID: chatID, 11 | status: true, 12 | welcome: welcome, 13 | }); 14 | return; 15 | } 16 | await settings.updateOne({ chatID: chatID }, { $set: { welcome: welcome } }); 17 | } 18 | 19 | export async function setStatus(chatID: number, status: boolean) { 20 | const chat = await settings.findOne({ chatID: chatID }); 21 | if (!chat) { 22 | await settings.insertOne({ chatID: chatID, status: status, welcome: "" }); 23 | return; 24 | } 25 | await settings.updateOne({ chatID: chatID }, { $set: { status: status } }); 26 | } 27 | 28 | export async function getSettings(chatID: number) { 29 | const chatsetting = await settings.find({ chatID: chatID }).toArray(); 30 | return chatsetting[0] ?? null; 31 | } 32 | 33 | export async function getAllSettings() { 34 | const chatsetting = await settings.find({}).toArray(); 35 | return chatsetting; 36 | } 37 | -------------------------------------------------------------------------------- /src/modules/langSettings.ts: -------------------------------------------------------------------------------- 1 | import { getAvaialableLocalesButtons } from "../helpers/functions.ts"; 2 | import { getLanguageInfo } from "language"; 3 | import { MyContext } from "../core/types.ts"; 4 | 5 | import { Composer, InlineKeyboard } from "grammy/mod.ts"; 6 | 7 | const composer = new Composer(); 8 | 9 | // language settings 10 | composer.callbackQuery(/setlang_(.*)/, async (ctx) => { 11 | const locale = ctx.match![1]; 12 | await ctx.i18n.setLocale(locale); 13 | await ctx.editMessageText( 14 | `Language set to ${ 15 | getLanguageInfo(locale)?.nativeName ?? locale 16 | }\n\nUse the buttons to change it again!`, 17 | { reply_markup: getAvaialableLocalesButtons(locale) }, 18 | ); 19 | await ctx.answerCallbackQuery(); 20 | }); 21 | 22 | composer 23 | .callbackQuery("setLang", async (ctx) => { 24 | const currentLocale = ctx.session?.__language_code ?? "en"; 25 | const keyboard = getAvaialableLocalesButtons(currentLocale); 26 | await ctx.editMessageText("Please select the language you want to use:", { 27 | reply_markup: keyboard, 28 | }); 29 | }); 30 | 31 | composer.callbackQuery(/set_locale_(.*)/, async (ctx) => { 32 | const i = ctx.match?.[0]; 33 | if (!i || i == undefined) return; 34 | await ctx.editMessageText(`Locale changed to ${i}`); 35 | await ctx.i18n.setLocale(i); 36 | }); 37 | 38 | export default composer; 39 | -------------------------------------------------------------------------------- /locales/ar.ftl: -------------------------------------------------------------------------------- 1 | start-msg = مرحبا {$user}! 2 | أنا روبوت إجراءات القناة, يركز الروبوت بشكل أساسي على العمل مع الجديد موافقة المشرف على روابط الدعوة. 3 | أنا استطيع: 4 | - الموافقة التلقائية على طلبات الانضمام الجديدة 5 | - رفض تلقائي لطلبات الانضمام الجديدة. 6 | انقر فوق الزر أدناه لمعرفة كيفية استخدامي! 7 | help = تعليمات الاستخدام. 8 | 9 | أضفني إلى قناتك كمسؤول ، مع إذن "إضافة مستخدمين" ، وإعادة توجيه رسالة إليّ من تلك الدردشة لإعدادني! 10 | 11 | usage-help = كيف تستعملني ❓ 12 | updates = التحديثات 13 | no-perms = إما لم تتم إضافتي في الدردشة كمسؤول ، أو أنك لست مسؤولاً في الدردشة! 14 | not-admin = أنت لست مسؤول في الدردشة! 15 | btn-approve = قبول الأعضاء الجدد 16 | btn-disapprove = ارفض الأعضاء الجدد 17 | btn-custom = رسالة ترحيب مخصصة 18 | chat-settings = *إعدادات {$title}* 19 | الاعدادات الحالية: 20 | الموافقة التلقائية: {$autoappr}. 21 | chat-settings-approved = تم تحديث الإعدادات! طلبات جديدة للانضمام للقناة {$title} ستتم الموافقة عليه تلقائيًا! 22 | chat-settings-disapproved = تم تحديث الإعدادات! طلبات الانضمام الجديدة في القناة {$title} سيتم رفضه تلقائيًا! 23 | welcome-text = أدخل رسالة الترحيب التي تريد أن يتلقاها الأعضاء الجدد المعتمدين / المرفوضين. 24 | التنسيقات المتوفرة: 25 | - $name - اسم المستخدمين. 26 | - $chat - عنوان الدردشة. 27 | provide-msg = يرجى تقديم رسالة! 28 | welcome-set = تم تعيين رسالة الترحيب على: 29 | {$msg} 30 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "Channel Actions Bot - Installer." 3 | echo "This script will install the bot and all its dependencies, and use pm2 to create a process to run the bot." 4 | 5 | echo "Updating system.." 6 | apt-get update 7 | apt-get upgrade -y 8 | 9 | echo "Installing dependencies.." 10 | apt install unzip npm -y 11 | curl -fsSL https://deno.land/x/install/install.sh | sh 12 | 13 | echo "Cloning the repository.." 14 | git clone https://github.com/xditya/ChannelActionsBot 15 | cd ChannelActionsBot 16 | 17 | echo "Making a .env file.." 18 | read -p "Enter your telegram bot token: " token 19 | read -p "Enter telegram user IDs to be owners. (separate by space): " owners 20 | read -p "Enter your MongoDB.com database URL: " dburl 21 | 22 | # https://stackoverflow.com/a/13633682/15249128 23 | cat > .env << EOF 24 | BOT_TOKEN=$token 25 | OWNERS=$owners 26 | MONGO_URL=$dburl 27 | EOF 28 | 29 | echo "Installing pm2.." 30 | npm install pm2 --location=global 31 | 32 | echo "Starting the bot.." 33 | if [ "$EUID" -ne 0 ] 34 | then 35 | path="/home/$(whoami)/.deno/bin/deno" 36 | else 37 | path="/root/.deno/bin/deno" 38 | fi 39 | 40 | pm2 start main.ts --interpreter=$path --interpreter-args="run --allow-env --allow-net --allow-read --no-prompt" --name "ChannelActions" -- --polling 41 | 42 | echo "Bot has started. View logs using 'pm2 logs ChannelActions'" 43 | echo "" 44 | echo "Join @BotzHub for more bots." 45 | echo "Know more: https://channelactions.xditya.me" 46 | echo "Thanks for using Channel Actions Bot!" -------------------------------------------------------------------------------- /src/modules/start.ts: -------------------------------------------------------------------------------- 1 | import { MyContext } from "../core/types.ts"; 2 | import { addUser } from "../database/usersDb.ts"; 3 | 4 | import { Composer, InlineKeyboard } from "grammy/mod.ts"; 5 | 6 | const composer = new Composer(); 7 | 8 | composer 9 | .command("start", async (ctx) => { 10 | if (ctx.chat.type != "private" && ctx.match == "by_BotzHub") { 11 | await ctx.reply("Continue setting me up in PM!", { 12 | reply_markup: new InlineKeyboard().url( 13 | "Continue", 14 | `https://t.me/${ctx.me.username}`, 15 | ), 16 | }); 17 | return; 18 | } 19 | if (ctx.chat.type != "private") return; 20 | await ctx.reply(ctx.t("start-msg", { user: ctx.from!.first_name }), { 21 | parse_mode: "HTML", 22 | reply_markup: new InlineKeyboard() 23 | .text(ctx.t("usage-help"), "helper") 24 | .text("Language 🌐", "setLang").row() 25 | .url(ctx.t("updates"), "https://t.me/BotzHub"), 26 | disable_web_page_preview: true, 27 | }); 28 | await addUser(ctx.from!.id); 29 | }); 30 | 31 | composer.callbackQuery("mainMenu", async (ctx) => { 32 | await ctx.editMessageText( 33 | ctx.t("start-msg", { user: ctx.from!.first_name }), 34 | { 35 | parse_mode: "HTML", 36 | reply_markup: new InlineKeyboard() 37 | .text(ctx.t("usage-help"), "helper") 38 | .text("Language 🌐", "setLang").row() 39 | .url(ctx.t("updates"), "https://t.me/BotzHub"), 40 | disable_web_page_preview: true, 41 | }, 42 | ); 43 | }); 44 | 45 | export default composer; 46 | -------------------------------------------------------------------------------- /locales/en.ftl: -------------------------------------------------------------------------------- 1 | start-msg = Hi {$user}! 2 | I'm Channel Actions Bot, a bot mainly focused on working with the new admin approval invite links. 3 | 4 | I can: 5 | - Auto approve new join requests 6 | - Auto Decline New Join Requests. 7 | 8 | Click the below button to know how to use me! 9 | 10 | help = Usage instructions. 11 | 12 | Add me to your channel as administrator, with "add users" permission, and forward me a message from that chat to set me up! 13 | 14 | usage-help = How to use me ❓ 15 | 16 | updates = Updates 17 | 18 | no-perms = Either I am not added in the chat as admin, or you are not an admin in the chat! 19 | 20 | not-admin = You are not an admin in the chat! 21 | 22 | btn-approve = Approve New Members 23 | 24 | btn-disapprove = Disapprove New Members 25 | 26 | btn-custom = Custom Welcome Message 27 | 28 | chat-settings = *Settings for {$title}* 29 | 30 | Current settings: 31 | AutoApprove: {$autoappr}. 32 | 33 | chat-settings-approved = Settings updated! New join requests in the channel {$title} will be approved automatically! 34 | 35 | chat-settings-disapproved = Settings updated! New join requests in the channel {$title} will be disapproved automatically! 36 | 37 | welcome-text = Enter the welcome message you want the new approved/disapproved members to receive. 38 | 39 | Available formattings: 40 | - $name - users name. 41 | - $chat - chat title. 42 | 43 | provide-msg = Please provide a message! 44 | 45 | welcome-set = Welcome message set to: 46 | {$msg} 47 | -------------------------------------------------------------------------------- /locales/or.ftl: -------------------------------------------------------------------------------- 1 | start-msg = ନମସ୍କାର {$user}! 2 | ମୁଁ ଚ୍ୟାନେଲ୍ ଆକ୍ସନ୍ ବଟ୍, ଏକ ବଟ୍ ମୁଖ୍ୟତ ନୂତନ ସହିତ କାମ କରିବା ଉପରେ ଧ୍ୟାନ ଦେଇଥାଏ ଆଡମିନ୍ ଅନୁମୋଦନ ଲିଙ୍କ୍ ଆମନ୍ତ୍ରଣ କରେ. 3 | ମୁଁ: 4 | - ନୂତନ ଯୋଗଦାନ ଅନୁରୋଧଗୁଡିକ ଅଟୋ ଅନୁମୋଦନ ପାରିବି 5 | - ଏବଂ ନୂତନ ଯୋଗଦାନ ଅନୁରୋଧଗୁଡିକ ଅଟୋ ପ୍ରତ୍ୟାଖ୍ୟାନ ପାରିବି । 6 | ମୋତେ କିପରି ବ୍ୟବହାର କରିବେ ଜାଣିବା ପାଇଁ ନିମ୍ନ ବଟନ୍ କ୍ଲିକ୍ କରନ୍ତୁ! 7 | help = ବ୍ୟବହାର ନିର୍ଦ୍ଦେଶାବଳୀ । 8 | 9 | ଆଡମିନିଷ୍ଟ୍ରେଟର ଭାବରେ ମୋତେ ଆପଣଙ୍କର ଚ୍ୟାନେଲ୍ ରେ ଯୋଡନ୍ତୁ, "add users" ଅଧିକାର ସହିତ, ଏବଂ ମୋତେ ସେଟ୍ ଅପ୍ କରିବାକୁ ସେହି ଚାଟ୍ରୁ ଏକ ବାର୍ତ୍ତା ପଠାନ୍ତୁ! 10 | 11 | usage-help = ମୋତେ କିପରି ବ୍ୟବହାର କରିବେ ❓ 12 | updates = ଅପ୍ଡେଟ୍ସ 13 | no-perms = ନା ମୁଁ ଚାଟ୍ ରେ ଆଡମିନ ଭାବରେ ଯୋଡି ହୋଇନାହିଁ, କିମ୍ବା ଆପଣ ଚାଟ୍ ରେ ଜଣେ ଆଡମିନ ନୁହଁନ୍ତି! 14 | not-admin = ଆପଣ ଚାଟ୍ ର ଜଣେ ଆଡମିନି ନୁହଁନ୍ତି! 15 | btn-approve = ନୂତନ ସଦସ୍ୟମାନଙ୍କୁ ଅନୁମୋଦନ କରନ୍ତୁ 16 | btn-disapprove = ନୂତନ ସଦସ୍ୟମାନଙ୍କୁ ଅନୁମୋଦନ କରନ୍ତୁ 17 | btn-custom = କଷ୍ଟମ୍ ସ୍ୱାଗତ ବାର୍ତ୍ତା 18 | chat-settings = *{$title} ପାଇଁ ସେଟିଂସମୂହ* 19 | ଚଳିତ ସେଟିଂସମୂହ: 20 | AutoApprove: {$autoappr}. 21 | chat-settings-approved = ସେଟିଂସମୂହ ଅଦ୍ୟତନ ହୋଇଛି! {$title} ଚ୍ୟାନେଲ୍ ରେ ନୂତନ ଯୋଗଦାନ ଅନୁରୋଧ ସ୍ୱୟଂଚାଳିତ ଭାବରେ ଅନୁମୋଦିତ ହେବ! 22 | chat-settings-disapproved = ସେଟିଂସମୂହ ଅଦ୍ୟତନ ହୋଇଛି! {$title} ଚ୍ୟାନେଲ୍ ରେ ନୂତନ ଯୋଗଦାନ ଅନୁରୋଧ ସ୍ୱୟଂଚାଳିତ ଭାବରେ ନାପସନ୍ଦ ହେବ! 23 | welcome-text = ଆପଣ ନୂତନ ଅନୁମୋଦିତ / ନାପସନ୍ଦ ସଦସ୍ୟ ଗ୍ରହଣ କରିବାକୁ ଚାହୁଁଥିବା ସ୍ୱାଗତ ବାର୍ତ୍ତା ପ୍ରବେଶ କରନ୍ତୁ | 24 | ଉପଲବ୍ଧ ଫର୍ମାଟିଂ: 25 | - $name - ବ୍ୟବହାରକାରୀଙ୍କ ନାମ । 26 | - $chat - ଚାଟ୍ ଟାଇଟଲ୍ | 27 | provide-msg = ଦୟାକରି ଏକ ବାର୍ତ୍ତା ପ୍ରଦାନ କରନ୍ତୁ! 28 | welcome-set = ସ୍ୱାଗତ ବାର୍ତ୍ତା ଏହାକୁ ସେଟ୍ ହୋଇଛି: 29 | {$msg} 30 | -------------------------------------------------------------------------------- /locales/bn.ftl: -------------------------------------------------------------------------------- 1 | start-msg = হাই {$user}! 2 | আমি চ্যানেল অ্যাকশন বট, একটি বট প্রধানত নতুন অ্যাডমিন অনুমোদনের আমন্ত্রণ লিঙ্কগুলির সাথে কাজ করার উপর ফোকাস করে। 3 | 4 | আমি পারি: 5 | - নতুন যোগদানের অনুরোধ অটো অনুমোদন করতে 6 | - নতুন যোগদানের অনুরোধ অটো প্রত্যাখ্যান করতে। 7 | 8 | আমাকে কীভাবে ব্যবহার করবেন তা জানতে নীচের বাটনে ক্লিক করুন! 9 | 10 | help = ব্যবহারের নির্দেশাবলী। 11 | 12 | আমাকে আপনার চ্যানেলে অ্যাডমিনিস্ট্রেটর হিসেবে যোগ করুন, "ব্যবহারকারী যোগ করার" অনুমতি সহ, এবং আমাকে সেট আপ করার জন্য সেই চ্যাট থেকে একটি বার্তা ফরওয়ার্ড করুন! 13 | 14 | usage-help = আমাকে কিভাবে ব্যবহার করবেন ❓ 15 | 16 | updates = আপডেট 17 | 18 | no-perms = হয় আমাকে চ্যাটে অ্যাডমিন হিসেবে নিযুক্ত করা হয়নি, অথবা আপনি চ্যাটে অ্যাডমিন নন! 19 | 20 | not-admin = চ্যাটে আপনি অ্যাডমিন নন! 21 | 22 | btn-approve = নতুন সদস্যদের অনুমোদন করুন 23 | 24 | btn-disapprove = নতুন সদস্যদের বাতিল করুন 25 | 26 | btn-custom = কাস্টম স্বাগতম বার্তা 27 | 28 | chat-settings = *{$title} এর সেটিংস* 29 | 30 | বর্তমান সেটিংস: 31 | AutoApprove: {$autoappr}. 32 | 33 | chat-settings-approved = সেটিংস আপডেট! চ্যানেলের {$title} নতুন যোগদানের অনুরোধ স্বয়ংক্রিয়ভাবে গ্রহণ করা হবে! 34 | 35 | chat-settings-disapproved = সেটিংস আপডেট! চ্যানেলের {$title} নতুন যোগদানের অনুরোধ স্বয়ংক্রিয়ভাবে বাতিল করা হবে! 36 | 37 | welcome-text = আপনি যে স্বাগত বার্তাটি নতুন অনুমোদিত/অননুমোদিত সদস্যদের পাঠাতে চান তা লিখুন। 38 | 39 | প্রাপ্তিসাধ্য বিন্যাস: 40 | - $name - ব্যবহারকারীর নাম। 41 | - $chat - চ্যাট টাইটেল। 42 | 43 | provide-msg = একটি বার্তা প্রদান করুন! 44 | 45 | welcome-set = স্বাগত বার্তা সেট করা হয়েছে: 46 | {$msg} 47 | -------------------------------------------------------------------------------- /locales/tr.ftl: -------------------------------------------------------------------------------- 1 | start-msg = Merhaba {$user}! 2 | Ben Kanal Eylemleri Botuyum , esas olarak yeni yönetici onayı davet bağlantılarıyla çalışmaya odaklanan bir bot. 3 | 4 | Şunları yapabilirim: 5 | - Yeni katılma isteklerini otomatik olarak onaylayabilir 6 | - Yeni Katılma İsteklerini Otomatik Olarak Reddetebilirim. 7 | 8 | Click the below button to know how to use me! 9 | 10 | help = Kullanım talimatları. 11 | 12 | "Kullanıcı ekle" izniyle beni kanalınıza yönetici olarak ekleyin ve beni ayarlamak için o sohbetten bana bir mesaj iletin! 13 | 14 | usage-help = Beni nasıl kullanırım ❓ 15 | 16 | updates = İzinsiz 17 | 18 | no-perms = Ya ben sohbete yönetici olarak eklenmedim ya da sen sohbette yönetici değilsin! 19 | 20 | not-admin = Sohbette yönetici değilsiniz! 21 | 22 | btn-approve = Yeni Üyeleri Onayla 23 | 24 | btn-disapprove = Yeni Üyeleri Reddet 25 | 26 | btn-custom = Özel Hoş Geldiniz Mesajı 27 | 28 | chat-settings = *{$title} için ayarlar* 29 | 30 | Mevcut ayarlar: 31 | Otomatik Onayla: {$autoappr}. 32 | 33 | chat-settings-approved = Ayarlar güncellendi! {$title} kanalındaki yeni katılma istekleri otomatik olarak onaylanacak! 34 | 35 | chat-settings-disapproved = Ayarlar güncellendi! {$title} kanalındaki yeni katılma istekleri otomatik olarak reddedilecek! 36 | 37 | welcome-text = Yeni onaylanmış/onaylanmamış üyelerin almasını istediğiniz karşılama mesajını girin. Kullanılabilir biçimlendirmeler: - $name - kullanıcı adı. - $chat - sohbet başlığı. 38 | 39 | welcome-msg = Lütfen bir mesaj verin! 40 | 41 | welcome-set = Karşılama mesajı şu şekilde ayarlandı: 42 | {$msg} 43 | -------------------------------------------------------------------------------- /locales/gu.ftl: -------------------------------------------------------------------------------- 1 | start-msg = હાય {$user}! 2 | હું ચેનલ એક્શન્સ બોટ છું , એક બોટ જે મુખ્યત્વે નવી એડમિન મંજૂરી આમંત્રણ લિંક્સ સાથે કામ કરવા પર કેન્દ્રિત છે. 3 | 4 | હું આ કરી શકું છું : 5 | - નવી જોડાવાની વિનંતીઓને સ્વતઃ મંજૂર કરી શકું 6 | - નવી જોડાવાની વિનંતીઓ 7 | 8 | સ્વતઃ નકારી શકાય. 9 | 10 | મારો ઉપયોગ કેવી રીતે કરવો તે જાણવા માટે નીચેના બટન પર ક્લિક કરો! 11 | 12 | help = ઉપયોગ માટેની સૂચનાઓ. 13 | 14 | મને તમારી ચેનલમાં એડમિનિસ્ટ્રેટર તરીકે ઉમેરો, "વપરાશકર્તાઓ ઉમેરો" પરવાનગી સાથે, અને મને સેટ કરવા માટે તે ચેટમાંથી એક સંદેશ ફોરવર્ડ કરો! 15 | 16 | usage-help = મારો ઉપયોગ કેવી રીતે કરવો ❓ 17 | 18 | updates = અપડેટ્સ 19 | 20 | no-perms = કાં તો મને ચેટમાં એડમિન તરીકે ઉમેરવામાં આવ્યો નથી, અથવા તમે ચેટમાં એડમિન નથી! 21 | 22 | not-admin = તમે ચેટમાં એડમિન નથી! 23 | 24 | btn-approve = નવા સભ્યોને મંજૂર કરો! 25 | 26 | btn-disapprove = નવા સભ્યોને નામંજૂર કરો! 27 | 28 | btn-custom = કસ્ટમ સ્વાગત સંદેશ! 29 | 30 | chat-settings = *{$title} માટે સેટિંગ્સ* 31 | 32 | વર્તમાન સેટિંગ્સ: 33 | સ્વતઃ મંજૂર કરો: {$autoappr}. 34 | 35 | chat-settings-approved = સેટિંગ્સ અપડેટ! ચેનલ {$title} માં જોડાવા માટેની નવી વિનંતીઓ આપમેળે મંજૂર કરવામાં આવશે! 36 | 37 | chat-settings-disapproved = સેટિંગ્સ અપડેટ! ચેનલ {$title} માં જોડાવાની નવી વિનંતીઓ આપમેળે નામંજૂર કરવામાં આવશે! 38 | 39 | welcome-text = નવા મંજૂર/અસ્વીકાર્ય સભ્યો પ્રાપ્ત થાય તે માટે તમે ઇચ્છો છો તે સ્વાગત સંદેશ દાખલ કરો. 40 | 41 | ઉપલબ્ધ ફોર્મેટિંગ: 42 | - $name - વપરાશકર્તાઓનું નામ. 43 | - $chat - ચેટ શીર્ષક. 44 | 45 | provide-msg = કૃપા કરીને સંદેશ આપો! 46 | 47 | welcome-set = સ્વાગત સંદેશ આના પર સેટ કરેલ છે: 48 | {$msg} 49 | -------------------------------------------------------------------------------- /locales/pn.ftl: -------------------------------------------------------------------------------- 1 | start-msg = Hi {$user}! 2 | 3 | ਮੈਂ ਚੈਨਲ ਐਕਸ਼ਨ ਬੋਟ ਹਾਂ, ਇੱਕ ਬੋਟ ਜੋ ਮੁੱਖ ਤੌਰ 'ਤੇ ਨਵੇਂ ਪ੍ਰਬੰਧਕ ਮਨਜ਼ੂਰੀ ਸੱਦਾ ਲਿੰਕਾਂ ਨਾਲ ਕੰਮ ਕਰਨ 'ਤੇ ਕੇਂਦਰਿਤ ਹੈ. 4 | ਮੈਂ ਕਰ ਸਕਦਾ ਹਾਂ: 5 | - ਸ਼ਾਮਲ ਹੋਣ ਦੀਆਂ ਨਵੀਆਂ ਬੇਨਤੀਆਂ ਨੂੰ ਸਵੈਚਲਿਤ ਤੌਰ 'ਤੇ ਮਨਜ਼ੂਰ ਕਰੋ 6 | - ਸ਼ਾਮਲ ਹੋਣ ਦੀਆਂ ਨਵੀਆਂ ਬੇਨਤੀਆਂ ਨੂੰ ਸਵੈਚਲਿਤ ਤੌਰ 'ਤੇ ਅਸਵੀਕਾਰ ਕਰੋ। 7 | ਮੈਨੂੰ ਕਿਵੇਂ ਵਰਤਣਾ ਹੈ ਇਹ ਜਾਣਨ ਲਈ ਹੇਠਾਂ ਦਿੱਤੇ ਬਟਨ 'ਤੇ ਕਲਿੱਕ ਕਰੋ! 8 | help = ਵਰਤੋਂ ਨਿਰਦੇਸ਼. 9 | 10 | "ਉਪਭੋਗਤਾ ਜੋੜੋ" ਅਨੁਮਤੀ ਦੇ ਨਾਲ, ਮੈਨੂੰ ਆਪਣੇ ਚੈਨਲ ਵਿੱਚ ਪ੍ਰਸ਼ਾਸਕ ਵਜੋਂ ਸ਼ਾਮਲ ਕਰੋ, ਅਤੇ ਮੈਨੂੰ ਸੈੱਟ ਕਰਨ ਲਈ ਉਸ ਚੈਟ ਤੋਂ ਇੱਕ ਸੁਨੇਹਾ ਅੱਗੇ ਭੇਜੋ! 11 | 12 | usage-help = ਮੈਨੂੰ ਕਿਵੇਂ ਵਰਤਣਾ ਹੈ ❓ 13 | updates = ਅੱਪਡੇਟ 14 | no-perms = ਜਾਂ ਤਾਂ ਮੈਨੂੰ ਚੈਟ ਵਿੱਚ ਐਡਮਿਨ ਵਜੋਂ ਸ਼ਾਮਲ ਨਹੀਂ ਕੀਤਾ ਗਿਆ ਹੈ, ਜਾਂ ਤੁਸੀਂ ਚੈਟ ਵਿੱਚ ਪ੍ਰਸ਼ਾਸਕ ਨਹੀਂ ਹੋ! 15 | not-admin = ਤੁਸੀਂ ਚੈਟ ਵਿੱਚ ਇੱਕ ਪ੍ਰਸ਼ਾਸਕ ਨਹੀਂ ਹੋ! 16 | btn-approve = ਨਵੇਂ ਮੈਂਬਰਾਂ ਨੂੰ ਮਨਜ਼ੂਰੀ ਦਿਓ 17 | btn-disapprove = ਨਵੇਂ ਮੈਂਬਰਾਂ ਨੂੰ ਨਾਮਨਜ਼ੂਰ ਕਰੋ 18 | btn-custom = ਕਸਟਮ ਸੁਆਗਤ ਸੁਨੇਹਾ 19 | chat-settings = *{$title} ਲਈ ਸੈਟਿੰਗਾਂ* 20 | Current settings: 21 | AutoApprove: {$autoappr}. 22 | chat-settings-approved = ਸੈਟਿੰਗਾਂ ਅੱਪਡੇਟ ਕੀਤੀਆਂ ਗਈਆਂ! ਚੈਨਲ {$title} ਵਿੱਚ ਸ਼ਾਮਲ ਹੋਣ ਦੀਆਂ ਨਵੀਆਂ ਬੇਨਤੀਆਂ ਨੂੰ ਆਪਣੇ ਆਪ ਮਨਜ਼ੂਰ ਕੀਤਾ ਜਾਵੇਗਾ! 23 | chat-settings-disapproved = ਸੈਟਿੰਗਾਂ ਅੱਪਡੇਟ ਕੀਤੀਆਂ ਗਈਆਂ! ਚੈਨਲ {$title} ਵਿੱਚ ਸ਼ਾਮਲ ਹੋਣ ਦੀਆਂ ਨਵੀਆਂ ਬੇਨਤੀਆਂ ਨੂੰ ਆਪਣੇ ਆਪ ਨਾਮਨਜ਼ੂਰ ਕਰ ਦਿੱਤਾ ਜਾਵੇਗਾ! 24 | welcome-text = ਉਹ ਸੁਆਗਤ ਸੁਨੇਹਾ ਦਾਖਲ ਕਰੋ ਜੋ ਤੁਸੀਂ ਚਾਹੁੰਦੇ ਹੋ ਕਿ ਨਵੇਂ ਪ੍ਰਵਾਨਿਤ/ਅਪ੍ਰਵਾਨਿਤ ਮੈਂਬਰਾਂ ਨੂੰ ਪ੍ਰਾਪਤ ਹੋਵੇ। 25 | Available formattings: 26 | - $name - users name. 27 | - $chat - chat title. 28 | provide-msg = ਕਿਰਪਾ ਕਰਕੇ ਇੱਕ ਸੁਨੇਹਾ ਪ੍ਰਦਾਨ ਕਰੋ! 29 | welcome-set = ਸੁਆਗਤ ਸੁਨੇਹਾ ਇਸ 'ਤੇ ਸੈੱਟ ਕੀਤਾ ਗਿਆ: 30 | {$msg} 31 | -------------------------------------------------------------------------------- /locales/as.ftl: -------------------------------------------------------------------------------- 1 | start-msg = নমস্কাৰ {$user}! 2 | মই চেনেল কাৰ্য্যকাৰ বট, বট, মুখ্যতঃ নতুন প্ৰশাসকৰ অনুমোদন আমন্ত্ৰণ লিংকসমূহ সৈতে কাম কৰাৰ ওপৰত গুৰুত্ব দিয়া হৈছে. 3 | 4 | মই কি কৰিব পাৰো: 5 | - স্বয়ংক্ৰিয়ভাৱে নতুন যোগদানঅনুৰোধ অনুমোদিত কৰা 6 | - স্বয়ংক্ৰিয়ভাৱে নতুন যোগদানঅনুৰোধ অস্বীকাৰ কৰা 7 | 8 | মোক কেনেদৰে ব্যৱহাৰ কৰিব লাগে জানিবলৈ তলৰ বুটামত ক্লিক কৰক! 9 | 10 | help = ব্যৱহাৰৰ নিৰ্দেশনাসমূহ. 11 | 12 | প্ৰশাসক হিচাপে মোক আপোনাৰ চেনেলত যোগ দিয়ক, "ব্যৱহাৰকাৰী যোগ কৰক" অনুমতিৰ সৈতে, আৰু মোক ছেট আপ কৰিবলৈ সেই চেটৰ পৰা এটা বাৰ্তা ফৰৱাৰ্ড কৰক! 13 | 14 | usage-help = মোক কেনেদৰে ব্যৱহাৰ কৰিব ❓ 15 | 16 | updates = সকলো আপডেট 17 | 18 | no-perms = হয় মোক এডমিন হিচাপে চেটত যোগ কৰা নহয়, নতুবা আপুনি চেটত এডমিন নহয়! 19 | 20 | not-admin = আপুনি চেটত এডমিন নহয়! 21 | 22 | btn-approve = নতুন সদস্যসকলক অনুমোদন কৰক 23 | 24 | btn-disapprove = নতুন সদস্যসকলক অস্বীকাৰ কৰক 25 | 26 | btn-custom = স্বনিৰ্বাচিত স্বাগতম বাৰ্তা 27 | 28 | chat-settings = *সংহতিসমূহ {$title}* 29 | 30 | বৰ্তমান সংহতিসমূহ: 31 | স্বয়ংঅনুমোদন: {$autoappr}. 32 | 33 | chat-settings-approved = ছেটিংছ আপডেট কৰা হৈছে! চেনেল {$title} ত নতুন যোগদান অনুৰোধ স্বয়ংক্ৰিয়ভাৱে অনুমোদিত হ'ব! 34 | 35 | chat-settings-disapproved = ছেটিংছ আপডেট কৰা হৈছে! চেনেল {$title} ত নতুন যোগদান অনুৰোধ স্বয়ংক্ৰিয়ভাৱে অস্বীকাৰ কৰা হ'ব! 36 | 37 | welcome-text = আপুনি নতুন অনুমোদিত/অস্বীকৃত সদস্যসকলে প্ৰাপ্ত কৰিব বিচৰা স্বাগতম বাৰ্তাপ্ৰবিষ্ট কৰক. 38 | 39 | উপলব্ধ ফৰ্মেটিং: 40 | - $name - ব্যৱহাৰকাৰীৰ নাম. 41 | - $chat - চেটৰ নাম. 42 | 43 | provide-msg = অনুগ্ৰহ কৰি এটা বাৰ্তা প্ৰদান কৰক! 44 | 45 | welcome-set = নতুন স্বাগতম বাৰ্তা ছেট কৰা হৈছে: 46 | {$msg} 47 | 48 | -------------------------------------------------------------------------------- /locales/mr.ftl: -------------------------------------------------------------------------------- 1 | start-msg = नमस्ते {$user}! 2 | मी चॅनल ऍक्शन बॉट आहे, एक बॉट मुख्यतः नवीन प्रशासक मंजूरी आमंत्रण लिंक सह काम करण्यावर केंद्रित आहे. 3 | 4 | मी काय करू शकतो?: 5 | - नवीन सामील होण्याच्या विनंत्या आपोआप मंजूर करणे, 6 | - नवीन सामील होण्याच्या विनंत्यांना स्वयं नकार देणे.. 7 | 8 | मला कसे वापरायचे हे जाणून घेण्यासाठी खालील बटणावर क्लिक करा! 9 | 10 | help = वापर सूचना. 11 | 12 | मला तुमच्या चॅनेलवर प्रशासक म्हणून जोडा, "नवीन मेंबर जोडा" परवानगीसह, आणि मला सेट करण्यासाठी त्या चॅटमधून एक संदेश फॉरवर्ड करा! 13 | 14 | usage-help = मला कसे वापरायचे ❓ 15 | 16 | updates = नवीनअपडेट्स 17 | 18 | no-perms = एकतर मला चॅटमध्ये प्रशासक म्हणून जोडले गेले नाही किंवा तुम्ही चॅटमध्ये प्रशासक नाही! 19 | 20 | not-admin = तुम्ही चॅटमध्ये प्रशासक नाही! 21 | 22 | btn-approve = नवीन सदस्य सामील होण्याच्या विनंत्या मंजूर करा. 23 | 24 | btn-disapprove = नवीन सदस्य सामील होण्याच्या विनंत्या नामंजूर करा. 25 | 26 | btn-custom = सानुकूल स्वागत संदेश 27 | 28 | chat-settings = *{$title} साठी सेटिंग्ज* 29 | 30 | वर्तमान सेटिंग्ज: 31 | स्वयं मंजूर: {$autoappr}. 32 | 33 | chat-settings-approved = सेटिंग्ज अपडेट केल्या! {$title} चॅनेलमध्ये सामील होण्याच्या नवीन विनंत्या आपोआप मंजूर केल्या जातील! 34 | 35 | chat-settings-disapproved = सेटिंग्ज अपडेट केल्या! {$title} चॅनेलमध्ये सामील होण्याच्या नवीन विनंत्या आपोआप नाकारल्या जातील! 36 | 37 | welcome-text = नवीन स्वीकृत/अस्वीकृत सदस्यांना प्राप्त व्हावे असा स्वागत संदेश प्रविष्ट करा. 38 | 39 | उपलब्ध स्वरूपन: 40 | - $name - वापरकर्ता नाव. 41 | - $chat - चॅट शीर्षक. 42 | 43 | provide-msg = कृपया एक संदेश द्या! 44 | 45 | welcome-set = स्वागत संदेश यावर सेट केला आहे: 46 | {$msg} 47 | -------------------------------------------------------------------------------- /locales/hi.ftl: -------------------------------------------------------------------------------- 1 | start-msg = नमस्ते {$user}! 2 | मैं चैनल ऐक्शन्स बॉट हूं, एक बॉट मुख्य रूप से नए एडमिन अनुमोदन आमंत्रण लिंक के साथ काम करने पर केंद्रित है. 3 | 4 | मैं कर सकता हूं: 5 | - नए ज्वाइन अनुरोधों को स्वचालित रूप से स्वीकृत 6 | - नए अनुरोध में शामिल होने के लिए स्वचालित रूप से अस्वीकार 7 | 8 | मुझे कैसे उपयोग करें यह जानने के लिए नीचे दिए गए बटन पर क्लिक करें! 9 | 10 | help = उपयोग के निर्देश. 11 | 12 | एक व्यवस्थापक के रूप में मुझे अपने चैनल में जोड़ें, "उपयोगकर्ताओं को जोड़ें" अनुमति के साथ, और मुझे सेट करने के लिए उस चैट से मुझे एक संदेश भेजें! 13 | 14 | usage-help = मुझे का उपयोग कैसे करें ❓ 15 | 16 | updates = अपडेट 17 | 18 | no-perms = या तो मैं चैट में एक व्यवस्थापक के रूप में नहीं जोड़ा गया है, या आप चैट में एक व्यवस्थापक नहीं हैं! 19 | 20 | not-admin = आप चैट में एक व्यवस्थापक नहीं हैं! 21 | 22 | btn-approve = नए सदस्यों को मंजूरी दें 23 | 24 | btn-disapprove = नए सदस्यों का बहिष्कार करें 25 | 26 | btn-custom = कस्टम वेलकम मैसेज 27 | 28 | chat-settings = *{$title} के लिए सेटिंग* 29 | 30 | मौजूदा सेटिंग: 31 | AutoApprove: {$autoappr}. 32 | 33 | chat-settings-approved = सेटिंग्स अपडेटेड! {$title} चैनल में नए ज्वॉइन अनुरोध स्वचालित रूप से मंजूर हो जाएंगे! 34 | 35 | chat-settings-disapproved = सेटिंग्स अपडेटेड! {$title} चैनल में नए ज्वॉइन अनुरोध स्वचालित रूप से नामंजूर हो जाएंगे! 36 | 37 | welcome-text = स्वागत संदेश दर्ज करें जिसे आप नए अनुमोदित/अस्वीकृत सदस्यों को प्राप्त करना चाहते हैं। 38 | 39 | उपलब्ध फॉर्मेटिंग: 40 | - $name - यूजर्स का नाम. 41 | - $chat - चैट टाइटल. 42 | 43 | provide-msg = कृपया एक संदेश प्रदान करें! 44 | 45 | welcome-set = स्वागत संदेश इस पर सेट किया गया हैः 46 | {$msg} 47 | -------------------------------------------------------------------------------- /locales/ne.ftl: -------------------------------------------------------------------------------- 1 | start-msg = नमस्ते {$user}! 2 | म च्यानल कार्य बोट हुँ, एउटा बट मुख्यतया नयाँ प्रशासक अनुमोदन आमन्त्रित लिङ्कहरू सँग काम गर्नमा केन्द्रित छ। 3 | 4 | म सक्छु: 5 | - नयाँ सामेल अनुरोधहरू स्वत: अनुमोदन गर्नुहोस् 6 | - नयाँ सामेल हुने अनुरोधहरू स्वत: अस्वीकार गर्नुहोस्। 7 | 8 | मलाई कसरी प्रयोग गर्ने भनेर जान्नको लागि तलको बटनमा क्लिक गर्नुहोस्! 9 | 10 | help = प्रयोग निर्देशनहरू। 11 | 12 | मलाई आफ्नो च्यानलमा प्रशासकको रूपमा थप्नुहोस्, "प्रयोगकर्ताहरू थप्नुहोस्" अनुमतिको साथ, र मलाई सेट अप गर्नको लागि त्यो च्याटबाट सन्देश फर्वार्ड गर्नुहोस्! 13 | 14 | usage-help = मलाई कसरी प्रयोग गर्ने ❓ 15 | 16 | updates = अपडेटहरू 17 | 18 | no-perms = या त मलाई च्याटमा प्रशासकको रूपमा थपिएको छैन, वा तपाईं च्याटमा प्रशासक हुनुहुन्न! 19 | 20 | not-admin = तपाईं च्याटमा प्रशासक हुनुहुन्न! 21 | 22 | btn-approve = नयाँ सदस्यहरूलाई अनुमोदन गर्नुहोस् 23 | 24 | btn-disapprove = नयाँ सदस्यहरूलाई अस्वीकार गर्नुहोस् 25 | 26 | btn-custom = अनुकूलन स्वागत सन्देश 27 | 28 | chat-settings = *{$title} को लागि सेटिङहरू* 29 | 30 | हालको सेटिङहरू: 31 | स्वतः अनुमोदन: {$autoappr} 32 | 33 | chat-settings-approved = सेटिङहरू अद्यावधिक गरियो! च्यानल {$title} मा सामेल हुने नयाँ अनुरोधहरू स्वतः स्वीकृत हुनेछन्! 34 | 35 | chat-settings-disapproved = सेटिङहरू अद्यावधिक गरियो! च्यानल {$title} मा नयाँ सामेल अनुरोधहरू स्वतः अस्वीकृत हुनेछन्! 36 | 37 | welcome-text = नयाँ स्वीकृत/अस्वीकृत सदस्यहरूले प्राप्त गर्न चाहेको स्वागत सन्देश प्रविष्ट गर्नुहोस्। 38 | 39 | उपलब्ध ढाँचाहरू: 40 | - $name - प्रयोगकर्ता नाम। 41 | - $chat - च्याट शीर्षक। 42 | 43 | provide-msg = कृपया सन्देश प्रदान गर्नुहोस्! 44 | 45 | welcome-set = स्वागत सन्देश सेट गरियो: 46 | {$msg} 47 | -------------------------------------------------------------------------------- /locales/da.ftl: -------------------------------------------------------------------------------- 1 | start-msg = Hej {$user}! 2 | Jeg er Channel Actions Bot, en bot, der hovedsageligt fokuserer på at arbejde med de nye admin-godkendelsesinvitationslinks. 3 | 4 | Jeg kan: 5 | - Godkend automatisk nye anmodninger om tilmelding 6 | - Afvis automatisk nye tilmeldingsanmodninger. 7 | 8 | Klik på knappen nedenfor for at vide, hvordan du bruger mig! 9 | 10 | help = Brugsvejledning. 11 | 12 | Tilføj mig til din kanal som administrator, med "tilføj brugere"-tilladelse, og videresend mig en besked fra den chat for at oprette mig! 13 | 14 | usage-help = Sådan bruger du mig ❓ 15 | 16 | updates = opdateringer 17 | 18 | no-perms = Enten er jeg ikke tilføjet i chatten som admin, eller også er du ikke admin i chatten! 19 | 20 | not-admin = Du er ikke administrator i chatten! 21 | 22 | btn-approve = Godkend nye medlemmer 23 | 24 | btn-disapprove = Afvis nye medlemmer 25 | 26 | btn-custom = Brugerdefineret velkomstbesked 27 | chat-settings = *Indstillinger for {$title}* 28 | 29 | Nuværende indstillinger: 30 | Autogodkend: {$autoappr}. 31 | 32 | chat-settings-approved = Indstillinger opdateret! Nye anmodninger om deltagelse i kanalen {$title} vil blive godkendt automatisk! 33 | 34 | chat-settings-disapproved = Indstillinger opdateret! Nye anmodninger om deltagelse i kanalen {$title} bliver automatisk afvist! 35 | 36 | welcome-text =Indtast den velkomstbesked, du ønsker, at de nye godkendte/afviste medlemmer skal modtage. 37 | 38 | Tilgængelige formateringer: 39 | - $name - brugernavn. 40 | - $chat - chat titel. 41 | 42 | provide-msg = Giv venligst en besked! 43 | 44 | welcome-set = Velkomstbesked indstillet til: 45 | {$msg} 46 | -------------------------------------------------------------------------------- /locales/id.ftl: -------------------------------------------------------------------------------- 1 | start-msg = Hai {$user}! 2 | Saya Channel Actions Bot, Bot ini fokus bekerja, terutama dengan undangan untuk persetujuan Admin baru. 3 | 4 | Saya bisa: 5 | - Menyetujui permintaan bergabung baru secara otomatis. 6 | - Tolak Otomatis Permintaan Bergabung Baru. 7 | 8 | Klik tombol di bawah ini untuk mengetahui cara menggunakan saya! 9 | 10 | help = Petunjuk penggunaan. 11 | 12 | Tambahkan saya ke saluran Anda sebagai administrator, dengan izin "tambah pengguna", dan teruskan ke saya pesan dari obrolan itu untuk menyiapkan saya! 13 | 14 | usage-help = Bagaimana cara menggunakan saya ❓ 15 | 16 | updates = Pembaruan 17 | 18 | no-perms = Entah saya tidak ditambahkan dalam obrolan sebagai admin, atau Anda bukan admin dalam obrolan! 19 | 20 | not-admin = Anda bukan admin dalam obrolan! 21 | 22 | btn-approve = Setujui Anggota Baru 23 | 24 | btn-disapprove = Tolak Anggota Baru 25 | 26 | btn-custom = Kustom Pesan Selamat Datang 27 | 28 | chat-settings = *Setelan untuk {$title}* 29 | 30 | Setelan saat ini: 31 | AutoApprove: {$autoappr}. 32 | 33 | chat-settings-approved = Setelan diperbarui! Permintaan bergabung baru di saluran {$title} akan disetujui secara otomatis! 34 | 35 | chat-settings-disapproved = Setelan diperbarui! Permintaan bergabung baru di saluran {$title} akan ditolak secara otomatis! 36 | 37 | welcome-text = Masukkan pesan selamat datang yang Anda inginkan untuk diterima oleh anggota baru yang disetujui/ditolak. 38 | 39 | Format yang tersedia: 40 | - $name - nama pengguna. 41 | - $chat - judul obrolan. 42 | 43 | provide-msg = Harap berikan pesan! 44 | 45 | welcome-set = Pesan selamat datang disetel ke: 46 | {$msg} 47 | -------------------------------------------------------------------------------- /locales/es.ftl: -------------------------------------------------------------------------------- 1 | start-msg = ¡Hola {$user}! 2 | Soy Channel Actions Bot, un bot centrado principalmente en trabajar con los nuevos enlaces de invitación con aprobación del administrador. 3 | Puedo: 4 | - Aprobar nuevas solicitudes de unión automáticamente. 5 | - Rechazar nuevas solicitudes de unión automáticamente. 6 | ¡Haz clic en el botón de abajo para aprender a usarme! 7 | help = Instrucciones de uso. 8 | 9 | Añádeme a tu canal como administrador, con el permiso de "añadir usuarios", ¡y reenvíame un mensaje de ese chat para ponerme a punto! 10 | 11 | usage-help = ¿Cómo utilizarme? ❓ 12 | updates = Actualizaciones 13 | no-perms = ¡O no estoy agregado al chat como administrador, o no eres un administrador en el chat! 14 | not-admin = ¡No eres un administrador en el chat! 15 | btn-approve = Aprobar nuevos miembros 16 | btn-disapprove = Rechazar nuevos miembros 17 | btn-custom = Mensaje de bienvenida personalizado 18 | chat-settings = *Ajustes de {$title}* 19 | Ajustes actuales: 20 | AutoAceptar: {$autoappr}. 21 | chat-settings-approved = ¡Los ajustes han sido actualizados! ¡Las nuevas solicitudes de unión en el canal {$title} se aprobarán automáticamente! 22 | chat-settings-disapproved = ¡Los ajustes han sido actualizados! ¡Las nuevas solicitudes de unión en el canal {$title} se rechazarán automáticamente! 23 | welcome-text = Introduce el mensaje de bienvenida que quieres que reciban los nuevos miembros aprobados/rechazados. 24 | Códigos de formato disponibles: 25 | - $name - el nombre del usuario. 26 | - $chat - el título del chat. 27 | provide-msg = ¡Por favor, indica un mensaje! 28 | welcome-set = Mensaje de bienvenida configurado como: 29 | {$msg} 30 | -------------------------------------------------------------------------------- /locales/kn.ftl: -------------------------------------------------------------------------------- 1 | start-msg = Hi {$user}! 2 | ನಾನು ಚಾನೆಲ್ ಆಕ್ಷನ್ಸ್ ಬಾಟ್, ಹೊಸ ನಿರ್ವಾಹಕರ ಅನುಮೋದನೆಯ ಆಹ್ವಾನ ಲಿಂಕ್‌ಗಳ ಜೊತೆಗೆ ಕೆಲಸ ಮಾಡುವುದರ ಮೇಲೆ ಪ್ರಮುಖವಾಗಿ ಗಮನಹರಿಸಿದ ಬಾಟ್.. 3 | 4 | ನಾನು: 5 | - ಹೊಸ ಸೇರ್ಪಡೆ ವಿನಂತಿಗಳನ್ನು ಸ್ವಯಂ ಅನುಮೋದಿಸಬಲ್ಲೆ 6 | - ಸ್ವಯಂ ನಿರಾಕರಣೆ ಹೊಸ ಸೇರ್ಪಡೆ ವಿನಂತಿಗಳು. 7 | 8 | ನನ್ನನ್ನು ಹೇಗೆ ಬಳಸುವುದು ಎಂದು ತಿಳಿಯಲು ಕೆಳಗಿನ ಬಟನ್ ಅನ್ನು ಕ್ಲಿಕ್ ಮಾಡಿ! 9 | 10 | help = ಬಳಕೆಯ ಸೂಚನೆಗಳು. 11 | 12 | "ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸು" ಅನುಮತಿಯೊಂದಿಗೆ ನನ್ನನ್ನು ನಿಮ್ಮ ಚಾನಲ್‌ಗೆ ನಿರ್ವಾಹಕರಾಗಿ ಸೇರಿಸಿ ಮತ್ತು ನನ್ನನ್ನು ಹೊಂದಿಸಲು ಆ ಚಾಟ್‌ನಿಂದ ನನಗೆ ಸಂದೇಶವನ್ನು ಫಾರ್ವರ್ಡ್ ಮಾಡಿ! 13 | 14 | usage-help = ನನ್ನನ್ನು ಹೇಗೆ ಬಳಸುವುದು ❓ 15 | 16 | updates = ಅಪ್ಡೇಟ್ಸ್ 17 | 18 | no-perms = ಒಂದೋ ನನ್ನನ್ನು ಚಾಟ್‌ನಲ್ಲಿ ನಿರ್ವಾಹಕರಾಗಿ ಸೇರಿಸಲಾಗಿಲ್ಲ, ಅಥವಾ ನೀವು ಚಾಟ್‌ನಲ್ಲಿ ನಿರ್ವಾಹಕರಾಗಿಲ್ಲ! 19 | 20 | not-admin = ನೀವು ಚಾಟ್‌ನಲ್ಲಿ ನಿರ್ವಾಹಕರಲ್ಲ! 21 | 22 | btn-approve = ಹೊಸ ಸದಸ್ಯರನ್ನು ಅನುಮೋದಿಸಿ 23 | 24 | btn-disapprove = ಹೊಸ ಸದಸ್ಯರನ್ನು ಅನುಮೋದಿಸಬೇಡಿ 25 | 26 | btn-custom = ಕಸ್ಟಮ್ ಸ್ವಾಗತ ಸಂದೇಶ 27 | 28 | chat-settings = *{$title}ಗಾಗಿ ಸೆಟ್ಟಿಂಗ್‌ಗಳು* 29 | 30 | ಪ್ರಸ್ತುತ ಸೆಟ್ಟಿಂಗ್‌ಗಳು: 31 | ಸ್ವಯಂ ಅನುಮೋದನೆ: {$autoappr}. 32 | 33 | chat-settings-approved = ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ನವೀಕರಿಸಲಾಗಿದೆ! {$title} ಚಾನಲ್‌ನಲ್ಲಿ ಹೊಸ ಸೇರ್ಪಡೆ ವಿನಂತಿಗಳನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಅನುಮೋದಿಸಲಾಗುತ್ತದೆ! 34 | 35 | chat-settings-disapproved = ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ನವೀಕರಿಸಲಾಗಿದೆ! {$title} ಚಾನಲ್‌ನಲ್ಲಿ ಹೊಸ ಸೇರ್ಪಡೆ ವಿನಂತಿಗಳನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಅನುಮೋದಿಸಲಾಗುತ್ತದೆ! 36 | 37 | welcome-text = ಹೊಸ ಅನುಮೋದಿತ/ಅನುಮೋದಿತ ಸದಸ್ಯರು ಸ್ವೀಕರಿಸಲು ನೀವು ಬಯಸುವ ಸ್ವಾಗತ ಸಂದೇಶವನ್ನು ನಮೂದಿಸಿ. 38 | 39 | ಲಭ್ಯವಿರುವ ಫಾರ್ಮ್ಯಾಟಿಂಗ್‌ಗಳು: 40 | - $name - ಬಳಕೆದಾರರ ಹೆಸರು. 41 | - $chat - ಚಾಟ್ ಶೀರ್ಷಿಕೆ. 42 | 43 | provide-msg = ದಯವಿಟ್ಟು ಸಂದೇಶವನ್ನು ಒದಗಿಸಿ! 44 | 45 | welcome-set = ಸ್ವಾಗತ ಸಂದೇಶವನ್ನು ಹೊಂದಿಸಲಾಗಿದೆ: 46 | {$msg} 47 | -------------------------------------------------------------------------------- /locales/ta.ftl: -------------------------------------------------------------------------------- 1 | start-msg = வணக்கம் {$user}! 2 | நான் சேனல் ஆக்ஷன்ஸ் பாட், புதிய நிர்வாக அனுமதி அழைப்பு இணைப்புகள் உடன் பணிபுரிவதில் முக்கியமாக கவனம் செலுத்தும் போட். 3 | என்னால் முடியும்: 4 | - புதிய சேருவதற்கான கோரிக்கைகளை தானாக அங்கீகரிக்கவும் 5 | - புதிய சேருவதற்கான கோரிக்கைகளைத் தானாக நிராகரித்தல். 6 | என்னைப் பயன்படுத்துவது எப்படி என்பதை அறிய கீழே உள்ள பொத்தானைக் கிளிக் செய்யவும்! 7 | help = பயன்பாட்டு வழிமுறைகள். 8 | 9 | "பயனர்களைச் சேர்" அனுமதியுடன் என்னை உங்கள் சேனலில் நிர்வாகியாகச் சேர்த்து, என்னை அமைக்க அந்த அரட்டையிலிருந்து ஒரு செய்தியை எனக்கு அனுப்பவும்! 10 | usage-help = என்னை எப்படி பயன்படுத்துவது ❓ 11 | updates = மேம்படுத்தல்கள் 12 | no-perms = ஒன்று நான் அரட்டையில் நிர்வாகியாக சேர்க்கப்படவில்லை, அல்லது நீங்கள் அரட்டையில் நிர்வாகி இல்லை! 13 | not-admin = நீங்கள் அரட்டையில் நிர்வாகி இல்லை! 14 | btn-approve = புதிய உறுப்பினர்களை அங்கீகரிக்கவும் 15 | btn-disapprove = புதிய உறுப்பினர்களை நிராகரிக்கவும் 16 | btn-custom = விருப்ப வரவேற்பு செய்தி 17 | chat-settings = *{$title}க்கான அமைப்புகள்* 18 | தற்போதைய அமைப்புகள்: 19 | தானியங்கு அனுமதி: {$autoappr}. 20 | chat-settings-approved = அமைப்புகள் புதுப்பிக்கப்பட்டன! {$title} சேனலில் சேரும் புதிய கோரிக்கைகள் தானாகவே அங்கீகரிக்கப்படும்! 21 | chat-settings-disapproved = அமைப்புகள் புதுப்பிக்கப்பட்டன! {$title} சேனலில் சேரும் புதிய கோரிக்கைகள் தானாகவே நிராகரிக்கப்படும்! 22 | welcome-text = புதிய அங்கீகரிக்கப்பட்ட/மறுக்கப்பட்ட உறுப்பினர்கள் பெற விரும்பும் வரவேற்பு செய்தியை உள்ளிடவும். 23 | கிடைக்கக்கூடிய வடிவமைப்புகள்: 24 | - $name - பயனர் பெயர். 25 | - $chat - அரட்டை தலைப்பு. 26 | provide-msg = தயவுசெய்து ஒரு செய்தியை வழங்கவும்! 27 | Welcome-set = வரவேற்பு செய்தி இதற்கு அமைக்கப்பட்டுள்ளது: 28 | {$msg} 29 | -------------------------------------------------------------------------------- /locales/te.ftl: -------------------------------------------------------------------------------- 1 | start-msg = హాయ్ {$user}! 2 | నేను ఛానెల్ చర్యల బాట్, కొత్త అడ్మిన్ ఆమోదం ఆహ్వాన లింక్‌లుతో పని చేయడంపై ప్రధానంగా దృష్టి సారించిన బాట్. 3 | 4 | నేను చేయగలను: 5 | - కొత్త చేరిక అభ్యర్థనలను స్వయంచాలకంగా ఆమోదించండి 6 | - కొత్త చేరిక అభ్యర్థనలను స్వయంచాలకంగా తిరస్కరించండి. 7 | 8 | నన్ను ఎలా ఉపయోగించాలో తెలుసుకోవడానికి దిగువ బటన్‌ను క్లిక్ చేయండి! 9 | 10 | help = వినియోగ సూచనలు. 11 | 12 | "వినియోగదారులను జోడించు" అనుమతితో నన్ను మీ ఛానెల్‌కి నిర్వాహకునిగా చేర్చుకోండి మరియు నన్ను సెటప్ చేయడానికి ఆ చాట్ నుండి ఒక సందేశాన్ని నాకు ఫార్వార్డ్ చేయండి! 13 | 14 | usage-help = నన్ను ఎలా ఉపయోగించాలి ❓ 15 | 16 | updates = నవీకరణలు 17 | 18 | no-perms = నేను చాట్‌లో అడ్మిన్‌గా జోడించబడలేదు లేదా మీరు చాట్‌లో అడ్మిన్ కాదు! 19 | 20 | not-admin = మీరు చాట్‌లో నిర్వాహకులు కాదు! 21 | 22 | btn-approve = కొత్త సభ్యులను ఆమోదించండి 23 | 24 | btn-disapprove = కొత్త సభ్యులను నిరాకరించు 25 | 26 | btn-custom = అనుకూల స్వాగత సందేశం 27 | 28 | chat-settings = *{$title} కోసం సెట్టింగ్‌లు* 29 | 30 | ప్రస్తుత సెట్టింగ్లు: 31 | స్వీయ ఆమోదం: {$autoappr}. 32 | 33 | chat-settings-approved = సెట్టింగ్‌లు నవీకరించబడ్డాయి! ఛానెల్ {$title}లో కొత్త చేరిక అభ్యర్థనలు స్వయంచాలకంగా ఆమోదించబడతాయి! 34 | 35 | chat-settings-disapproved = సెట్టింగ్‌లు నవీకరించబడ్డాయి! {$title} ఛానెల్‌లోని కొత్త చేరిక అభ్యర్థనలు స్వయంచాలకంగా తిరస్కరించబడతాయి! 36 | 37 | welcome-text = కొత్త ఆమోదించబడిన/నిరాకరణ సభ్యులు స్వీకరించాలనుకుంటున్న స్వాగత సందేశాన్ని నమోదు చేయండి. 38 | 39 | అందుబాటులో ఉన్న ఫార్మాటింగ్‌లు: 40 | - $name - వినియోగదారుల పేరు. 41 | - $chat - చాట్ శీర్షిక. 42 | 43 | provide-msg = దయచేసి ఒక సందేశాన్ని అందించండి! 44 | 45 | welcome-set = స్వాగత సందేశం దీనికి సెట్ చేయబడింది: 46 | {$msg} 47 | -------------------------------------------------------------------------------- /locales/ru.ftl: -------------------------------------------------------------------------------- 1 | start-msg = Привет {$user}! 2 | Я бот действий на канале. Этот бот в основном ориентирован на работу с новымиСсылки приглашения на одобрение администратора. 3 | 4 | Я могу: 5 | - Авто одобрение новых запросов на присоединение 6 | - Авто отклонение новых запросов на присоединение. 7 | 8 | Нажмите кнопку ниже, чтобы узнать, как использовать меня! 9 | 10 | helhelp = Инструкции по использованию. 11 | 12 | Добавьте меня на свой канал в качестве администратора с правом «добавить пользователей» и перешлите мне сообщение из этого чата, чтобы настроить меня! 13 | 14 | usage-help = Как использовать меня❓ 15 | 16 | updates = Обновления 17 | 18 | no-perms = Либо я не добавлен в чат как админ, либо вы не являетесь админом в чате! 19 | 20 | not-admin = Вы не являетесь админом в чате! 21 | 22 | btn-approve = Утвердить новых участников 23 | 24 | btn-disapprove = Отклонить новых участников 25 | 26 | btn-custom = Пользовательское приветственное сообщение 27 | 28 | chat-settings = *Настройки для {$title}* 29 | 30 | Текущие настройки: 31 | Автоодобрение: {$autoappr}. 32 | 33 | chat-settings-approved = Настройки обновлены! Новые запросы на вступление в канал {$title} будут одобрены автоматически! 34 | 35 | chat-settings-disapproved = Настройки обновлены! Новые запросы на вступление в канал {$title} будут автоматически отклонены! 36 | 37 | welcome-text = Введите приветственное сообщение, которое вы хотите, чтобы новые одобренные/отклоненные участники получали. 38 | 39 | Доступные форматирование: 40 | - $name - имя пользователя. 41 | - $chat - чат заглавие. 42 | 43 | provide-msg = Пожалуйста, предоставьте сообщение! 44 | 45 | welcome-set = Приветственное сообщение настроено на: 46 | {$msg} 47 | -------------------------------------------------------------------------------- /locales/ml.ftl: -------------------------------------------------------------------------------- 1 | start-msg =ഹായ് {$user}! 2 | ഞാൻ ചാനൽ ആക്ഷൻ ബോട്ടാണ്. 3 | ടെലിഗ്രാമിന്റെ പുതിയ അഡ്മിൻ അംഗീകരിക്കുന്ന ക്ഷണ ലിങ്കുകൾക്കൊപ്പം ഞാൻ പ്രവർത്തിക്കുന്നു 4 | 5 | എനിക്ക് കഴിയുന്നത്: 6 | - പുതിയ ചേരൽ അഭ്യർത്ഥനകൾ സ്വയമേവ അനുവദിക്കുക. 7 | - പുതിയ ചേരൽ അഭ്യർത്ഥനകൾ സ്വയമേവ നിരസിക്കുക. 8 | 9 | എന്നെ എങ്ങനെ ഉപയോഗിക്കണമെന്ന് അറിയാൻ താഴെയുള്ള ബട്ടൺ ക്ലിക്ക് ചെയ്യുക! 10 | 11 | help = ഉപയോഗ നിർദ്ദേശങ്ങൾ. 12 | 13 | "Add admins" അനുമതിയോടെ നിങ്ങളുടെ ചാനലിലേക്ക് എന്നെ അഡ്മിനിസ്ട്രേറ്ററായി ചേർക്കുക, എന്നെ സജ്ജീകരിക്കാൻ ആ ചാറ്റിൽ നിന്ന് ഒരു സന്ദേശം കൈമാറുക! 14 | 15 | usage-help = എന്നെ എങ്ങനെ ഉപയോഗിക്കാം ❓ 16 | 17 | updates = അപ്ഡേറ്റുകൾ 18 | 19 | no-perms = ഒന്നുകിൽ ഞാൻ ചാറ്റിൽ അഡ്മിനായി ചേർത്തിട്ടില്ല, അല്ലെങ്കിൽ നിങ്ങൾ ചാറ്റിൽ ഒരു അഡ്മിൻ അല്ല! 20 | 21 | not-admin = നിങ്ങൾ ചാറ്റിൽ ഒരു അഡ്മിൻ അല്ല! 22 | 23 | btn-approve = പുതിയ അംഗങ്ങളെ അംഗീകരിക്കുക 24 | 25 | btn-disapprove = പുതിയ അംഗങ്ങളെ അംഗീകരിക്കാതിരിക്കുക 26 | 27 | btn-custom = ഇഷ്ടാനുസൃത സ്വാഗത സന്ദേശം 28 | 29 | chat-settings = *{$title} എന്നതിനായുള്ള ക്രമീകരണങ്ങൾ* 30 | 31 | നിലവിലെ ക്രമീകരണങ്ങൾ: 32 | AutoApprove: {$autoappr}. 33 | 34 | chat-settings-approved = ക്രമീകരണങ്ങൾ അപ്ഡേറ്റ് ചെയ്തു! {$title} ചാനലിലെ പുതിയ ചേരൽ അഭ്യർത്ഥനകൾ സ്വയമേവ അംഗീകരിക്കപ്പെടും! 35 | 36 | chat-settings-disapproved = ക്രമീകരണങ്ങൾ അപ്ഡേറ്റ് ചെയ്തു! {$title} ചാനലിലെ പുതിയ ചേരൽ അഭ്യർത്ഥനകൾ സ്വയമേവ നിരാകരിക്കപ്പെടും! 37 | 38 | welcome-text = പുതിയ അംഗീകൃത/അംഗീകാരമില്ലാത്ത അംഗങ്ങൾക്ക് ലഭിക്കണമെന്ന് നിങ്ങൾ ആഗ്രഹിക്കുന്ന സ്വാഗത സന്ദേശം നൽകുക. 39 | 40 | ലഭ്യമായ ഫോർമാറ്റിംഗുകൾ: 41 | - $name - ഉപയോക്താക്കളുടെ പേര്. 42 | - $chat - ചാറ്റ് ശീർഷകം. 43 | 44 | provide-msg = ദയവായി ഒരു സന്ദേശം നൽകുക! 45 | 46 | welcome-set = സ്വാഗത സന്ദേശം ഇതിലേക്ക് സജ്ജമാക്കി: 47 | {$msg} -------------------------------------------------------------------------------- /locales/it.ftl: -------------------------------------------------------------------------------- 1 | start-msg = Ciao {$user}! 2 | Sono Channel Actions Bot, un bot focalizzato principalmente sul lavoro con i nuovi link di invito con l'approvazione dell'amministratore. 3 | 4 | Io posso: 5 | - Approvare automaticamente le nuove richieste di iscrizione 6 | - Rifiutare automaticamente le nuove richieste di iscrizione. 7 | 8 | Fai clic sul pulsante in basso per sapere come usarmi! 9 | 10 | help = Istruzioni per l'uso. 11 | 12 | Aggiungimi al tuo canale come amministratore, con il permesso "aggiungi utenti", e inoltrami un messaggio da quella chat per configurarmi! 13 | 14 | usage-help = Come usarmi ❓ 15 | 16 | updates = Aggiornamenti 17 | 18 | no-perms = O non sono stato aggiunto nella chat come admin, o tu non sei un admin nella chat! 19 | 20 | not-admin = Non sei un amministratore nella chat! 21 | 22 | btn-approve = Approva Nuovi Membri 23 | 24 | btn-disapprove = Rifiuta Nuovi Membri 25 | 26 | btn-custom = Messaggio di Benvenuto Personalizzato 27 | 28 | chat-settings = *Impostazioni per {$title}* 29 | 30 | Impostazioni attuali: 31 | AutoApprova: {$autoappr}. 32 | 33 | chat-settings-approved = Impostazioni aggiornate! Le nuove richieste di adesione nel canale {$title} saranno approvate automaticamente! 34 | 35 | chat-settings-disapproved = Impostazioni aggiornate! Le nuove richieste di adesione nel canale {$title} verranno automaticamente rifiutate! 36 | 37 | welcome-text = Inserisci il messaggio di benvenuto che desideri che i nuovi membri approvati/rifiutati ricevano.. 38 | 39 | Formattazioni disponibili: 40 | - $name - nome utente. 41 | - $chat - titolo chat. 42 | 43 | provide-msg = Per favore invia un messaggio! 44 | 45 | welcome-set = Messaggio di benvenuto impostato in: 46 | {$msg} 47 | -------------------------------------------------------------------------------- /locales/de.ftl: -------------------------------------------------------------------------------- 1 | start-msg = Hallo {$user}! 2 | Ich bin Channel Actions Bot, Ein Bot, der sich hauptsächlich auf die Arbeit mit dem Neuen konzentriert Einladungslinks zur Genehmigung durch den Administrator. 3 | 4 | ich kann: 5 | - Neue Beitrittsanfragen automatisch genehmigen 6 | - Neue Beitrittsanfragen automatisch ablehnen. 7 | 8 | Klicken Sie auf die Schaltfläche unten, um zu erfahren, wie Sie mich verwenden können! 9 | 10 | help = Gebrauchsanweisung. 11 | 12 | Füge mich als Administrator zu deinem Kanal hinzu, mit "Benutzer hinzufügen" Erlaubnis, und leiten Sie mir eine Nachricht aus diesem Chat weiter, um mich einzurichten!/popup.html 13 | 14 | usage-help = Wie man mich benutzt❓ 15 | 16 | updates = Aktualisierung 17 | 18 | no-perms = Entweder bin ich nicht als Admin im Chat eingetragen, oder du bist kein Admin im Chat! 19 | 20 | not-admin = Du bist kein Admin im Chat! 21 | 22 | btn-approve = Neue Mitglieder genehmigen 23 | 24 | btn-disapprove = Neue Mitglieder ablehnen 25 | 26 | btn-custom = Benutzerdefinierte Willkommensnachricht 27 | 28 | chat-settings = *Einstellungen für {$title}* 29 | 30 | Aktuelle Einstellungen: 31 | AutoApprove: {$autoappr}. 32 | 33 | chat-settings-approved = Einstellungen aktualisiert! Neue Beitrittsanfragen im Kanal {$title} werden automatisch genehmigt! 34 | 35 | chat-settings-disapproved = Einstellungen aktualisiert! Neue Beitrittsanfragen im Kanal {$title} werden automatisch abgelehnt! 36 | 37 | welcome-text = Geben Sie die Willkommensnachricht ein, die die neuen genehmigten/abgelehnten Mitglieder erhalten sollen. 38 | 39 | Verfügbare Formatierungen: 40 | - $name - Benutzername. 41 | - $chat - Chat-Titel. 42 | 43 | provide-msg = Bitte hinterlassen Sie eine Nachricht! 44 | 45 | welcome-set = Willkommensnachricht eingestellt auf: 46 | {$msg} 47 | -------------------------------------------------------------------------------- /locales/fr.ftl: -------------------------------------------------------------------------------- 1 | start-msg = Bonjour {$user} ! 2 | Je suis Channel Actions Bot, un bot principalement axé sur l'utilisation des nouveaux liens d'invitation d'approbation par l'administrateur. 3 | 4 | Je peux : 5 | - Approuver automatiquement les nouvelles demandes d'adhésion 6 | - Refuser automatiquement les nouvelles demandes d'adhésion. 7 | 8 | Cliquez sur le bouton ci-dessous pour savoir comment m'utiliser ! 9 | 10 | help = Instructions d'utilisation. 11 | 12 | Ajoutez-moi à votre chaîne en tant qu'administrateur, avec l'autorisation "ajouter des utilisateurs", et transférez-moi un message depuis ce chat pour me configurer ! 13 | 14 | usage-help = Comment m'utiliser ❓ 15 | 16 | updates = mises à jour 17 | 18 | no-perms = Soit je ne suis pas ajouté dans le chat en tant qu'administrateur, soit vous n'êtes pas administrateur dans le chat ! 19 | 20 | not-admin = Vous n'êtes pas un administrateur du chat ! 21 | 22 | btn-approve = Approuver les nouveaux membres 23 | 24 | btn-disapprove = Désapprouver les nouveaux membres 25 | 26 | btn-custom = Message de bienvenue personnalisé 27 | 28 | chat-settings = *Paramètres pour {$title}* 29 | 30 | Paramètres actuels: 31 | Approbation automatique : {$autoappr}. 32 | 33 | chat-settings-approved = Paramètres mis à jour ! Les nouvelles demandes d'adhésion dans le canal {$title} seront approuvées automatiquement ! 34 | 35 | chat-settings-disapproved = Paramètres mis à jour ! Les nouvelles demandes de participation dans la chaîne {$title} seront automatiquement refusées ! 36 | 37 | welcome-text = Entrez le message de bienvenue que vous souhaitez que les nouveaux membres approuvés/désapprouvés reçoivent. 38 | 39 | Formats disponibles : 40 | - $name - nom des utilisateurs. 41 | - $chat - titre du chat. 42 | 43 | provide-msg = Veuillez fournir un message ! 44 | 45 | welcome-set = Message de bienvenue défini sur : 46 | {$msg} 47 | -------------------------------------------------------------------------------- /src/modules/chatJoins.ts: -------------------------------------------------------------------------------- 1 | import { MyContext } from "../core/types.ts"; 2 | import { getSettings } from "../database/welcomeDb.ts"; 3 | import helperClass from "../helpers/baseHelpers.ts"; 4 | 5 | import { Composer } from "grammy/mod.ts"; 6 | 7 | const composer = new Composer(); 8 | 9 | composer.on("chat_join_request", async (ctx) => { 10 | if (!ctx.update.chat_join_request) return; 11 | const update = ctx.update.chat_join_request; 12 | const settings = await getSettings(update.chat.id); 13 | let approve_or_not, welcome; 14 | const def_welcome_approve = 15 | "Hey {name}, your request to join {chat} has been approved!"; 16 | const def_welcome_decline = 17 | "Hey {name}, your request to join {chat} has been declined!"; 18 | 19 | if (settings == null) { 20 | approve_or_not = true; 21 | welcome = def_welcome_approve; 22 | } else { 23 | approve_or_not = settings.status; 24 | if (approve_or_not == true) { 25 | welcome = settings.welcome ?? def_welcome_approve; 26 | if (welcome == "") welcome = def_welcome_approve; 27 | } else { 28 | welcome = settings.welcome ?? def_welcome_decline; 29 | if (welcome == "") welcome = def_welcome_decline; 30 | } 31 | } 32 | 33 | // increment total users seen 34 | helperClass.TOTAL_USERS_SEEN += 1; 35 | 36 | // try to approve 37 | try { 38 | if (approve_or_not) { 39 | await ctx.api.approveChatJoinRequest(update.chat.id, update.from.id); 40 | } else { 41 | await ctx.api.declineChatJoinRequest(update.chat.id, update.from.id); 42 | } 43 | } catch (error) { 44 | if (error.error_code == 400 || error.error_code == 403) return; 45 | console.log("Error while approving user: ", error.message); 46 | return; 47 | } 48 | 49 | welcome += "\n\nSend /start to know more!"; 50 | welcome = welcome.replace("{name}", update.from.first_name).replace( 51 | "{chat}", 52 | update.chat.title, 53 | ).replace("$name", update.from.first_name).replace( 54 | "$chat", 55 | update.chat.title, 56 | ); 57 | 58 | // try to send a message 59 | try { 60 | await ctx.api.sendMessage( 61 | update.user_chat_id, 62 | welcome, 63 | ); 64 | } catch (error) { 65 | if (error.error_code == 403) return; 66 | console.log("Error while sending a message: ", error.message); 67 | return; 68 | } 69 | }); 70 | 71 | export default composer; 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ChannelActionsBot 2 | 3 | Can be found on telegram as 4 | [@ChannelActionsBot](https://t.me/ChannelActionsBot)! 5 | 6 | ## Features 7 | 8 | - Auto Approve new join requests. 9 | - Auto Decline new join requests. 10 | - Custom welcome messages. 11 | 12 | ## Local Hosting 13 | 14 | [![DigitalOcean Referral Badge](https://web-platforms.sfo2.digitaloceanspaces.com/WWW/Badge%203.svg)](https://www.digitalocean.com/?refcode=7b7d6a915392&utm_campaign=Referral_Invite&utm_medium=Referral_Program&utm_source=badge) 15 | 16 | Requirements: 17 | 18 | 1. [Deno](https://deno.land/manual/getting_started/installation) 19 | 2. npm (for pm2) (skip if you plan to [use systemd](https://grammy.dev/hosting/vps.html#systemd)) 20 | 21 | ### Using PM2 22 | 23 | > **Note** 24 | > The below command will install deno, npm and pm2. You do not have to manually install them. 25 | 26 | ``` 27 | wget https://raw.githubusercontent.com/xditya/ChannelActionsBot/deno/install.sh && bash install.sh 28 | ``` 29 | 30 | > **Warning** 31 | > This command is only for the first run. 32 | 33 | > **Note** 34 | > Fill up the enviromnent vars as in [.env.sample](./.env.sample) when a nano editor is opened. Use CTRL+S and CTRL+X to save and exit, and continue installation. 35 | 36 | > **Note** 37 | > For viewing logs, use `pm2 logs ChannelActions` 38 | 39 | ## Deno Deploy 40 | 41 | [![Deploy Now!](https://img.shields.io/badge/Deploy%20Now-Deno%20Deploy-blue?style=for-the-badge&logo=deno)](https://dash.deno.com/new?url=https://raw.githubusercontent.com/xditya/ChannelActionsBot/deno/main.ts&env=BOT_TOKEN,OWNERS,MONGO_URL) 42 | 43 | > [Watch the video tutorial on deploying!](https://youtu.be/hjxfJtk5ZWs) 44 | 45 | 1. Open [deno deploy](https://dash.deno.com/), create a new project. 46 | 2. [Fork](https://github.com/xditya/ChannelActionsBot/fork) the `deno` branch of 47 | this repo. 48 | 3. Search for this repo on deno deploy, set branch as deno, set file as 49 | `main.ts` 50 | 4. Add your environment vars and click "Link". 51 | 5. Once done, open the deployment page, copy deployment URL, set your bot's 52 | webhook using 53 | `https://api.telegram.org/bot/setWebhook?url=/`. 54 | 55 | ## Translating 56 | 57 | > The bot now has multi-language support. You can pr your local language to this 58 | > repo! 59 | 60 | ### How to translate? 61 | 62 | 1. Go to the [locales folder](./locales). 63 | 2. Open any file, say [en.ftl](./locales/en.ftl). 64 | 3. Copy the contents, make a new file under the locales directory, named 65 | `lang_code.ftl`, where `lang_code` is your language code. 66 | 4. Edit the text in the new file, save it and make a pull request to this 67 | repository. 68 | 5. That's it! The pr will be tested and merged. 69 | 70 | ## Support 71 | 72 | - Telegram, [@BotzHubChat](https://t.me/BotzHubChat) 73 | 74 | ## Credits 75 | 76 | - [Me](https://xditya.me) for this bot. 77 | - [grammY](https://grammy.dev). 78 | -------------------------------------------------------------------------------- /main.ts: -------------------------------------------------------------------------------- 1 | /* 2 | ChannelActions Bot 3 | Telegram: @ChannelActionsBot 4 | 5 | (c) Aditya, https://xditya.me 6 | */ 7 | 8 | import config from "$env"; 9 | import composer from "./src/modules/mod.ts"; 10 | import { MyContext } from "./src/core/types.ts"; 11 | import { sessionsCollection } from "./src/database/sessionsDb.ts"; 12 | import i18n from "./src/core/i18n.ts"; 13 | 14 | import { serve } from "server"; 15 | import { 16 | Bot, 17 | GrammyError, 18 | HttpError, 19 | session, 20 | webhookCallback, 21 | } from "grammy/mod.ts"; 22 | import { autoQuote } from "autoQuote"; 23 | import { hydrate } from "hydrate"; 24 | import { MongoDBAdapter } from "mongo_sessions"; 25 | import { conversations, createConversation } from "conversations"; 26 | import { inputWelcomeMsg } from "./src/helpers/conversationHelpers.ts"; 27 | import { run } from "grammy_runner"; 28 | 29 | await i18n.loadLocalesDir("locales"); 30 | 31 | // initialize the bot 32 | const bot = new Bot(config.BOT_TOKEN); 33 | await bot.init(); 34 | 35 | bot.use(hydrate()); 36 | bot.use(autoQuote); 37 | bot.use( 38 | session({ 39 | initial: () => ({}), 40 | storage: new MongoDBAdapter({ collection: sessionsCollection }), 41 | }), 42 | ); 43 | bot.use(i18n); 44 | bot.use(conversations()); 45 | bot.use(createConversation(inputWelcomeMsg)); 46 | bot.use(composer); 47 | 48 | bot.catch((err) => { 49 | const ctx = err.ctx; 50 | console.error(`Error while handling update ${ctx.update.update_id}:`); 51 | const e = err.error; 52 | if (e instanceof GrammyError) { 53 | console.error("Error in request:", e.description); 54 | } else if (e instanceof HttpError) { 55 | console.error("Could not contact Telegram:", e); 56 | } else { 57 | console.error("Unknown error:", e); 58 | } 59 | }); 60 | 61 | if (Deno.args[0] == "--polling") { 62 | console.info(`Started as @${bot.botInfo.username} on long polling.`); 63 | 64 | // we use grammy's runner for concurrency 65 | // basically, on local hosts, for broadcast plugin 66 | // to work without killing the main bot process. 67 | 68 | const runner = run(bot, undefined, { 69 | allowed_updates: ["chat_join_request", "message", "callback_query"], 70 | }); 71 | const stopRunner = () => runner.isRunning() && runner.stop(); 72 | Deno.addSignalListener("SIGINT", stopRunner); 73 | Deno.addSignalListener( 74 | Deno.build.os != "windows" ? "SIGTERM" : "SIGINT", 75 | () => stopRunner, 76 | ); 77 | } else { 78 | console.info(`Started as @${bot.botInfo.username} on webhooks.`); 79 | 80 | const handleUpdate = webhookCallback(bot, "std/http"); 81 | serve(async (req) => { 82 | if (req.method === "POST") { 83 | const url = new URL(req.url); 84 | if (url.pathname.slice(1) === bot.token) { 85 | try { 86 | return await handleUpdate(req); 87 | } catch (err) { 88 | console.error(err); 89 | } 90 | } 91 | } 92 | return new Response("Welcome!"); 93 | }); 94 | } 95 | 96 | export default bot; 97 | -------------------------------------------------------------------------------- /src/modules/help.ts: -------------------------------------------------------------------------------- 1 | import { MyContext } from "../core/types.ts"; 2 | 3 | import { Composer, InlineKeyboard, Keyboard } from "grammy/mod.ts"; 4 | 5 | const composer = new Composer(); 6 | 7 | composer.callbackQuery("helper", async (ctx) => { 8 | try { 9 | await ctx.editMessageText( 10 | ctx.t("help") + 11 | "\n\nTo approve members who are already in waiting list, upgrade to premium! Contact @xditya_bot for information on pricing.", 12 | { 13 | reply_markup: new InlineKeyboard() 14 | .text("Add me to your channel", "add_to_channel") 15 | .text("Add me to your group", "add_to_group") 16 | .row() 17 | .text( 18 | "Main Menu 📭", 19 | "mainMenu", 20 | ), 21 | parse_mode: "HTML", 22 | }, 23 | ); 24 | } catch (err) { 25 | console.log(err); 26 | } 27 | }); 28 | 29 | composer.callbackQuery(/add_to_(.*)/, async (ctx) => { 30 | const channelOrGroup = ctx.match?.[1]; 31 | await ctx.editMessageText( 32 | "You can add me to channels as well as groups. Use the buttons below!", 33 | { 34 | reply_markup: new InlineKeyboard() 35 | .url( 36 | `Add to ${channelOrGroup}`, 37 | `https://t.me/${ctx.me.username}?start${channelOrGroup}=by_BotzHub&admin=invite_users+manage_chat`, 38 | ) 39 | .text("✅ Done", `select_${channelOrGroup}`).row() 40 | .text("« Back", "mainMenu"), 41 | }, 42 | ); 43 | }); 44 | 45 | composer.callbackQuery(/select_(.*)/, async (ctx) => { 46 | const channelOrGroup = ctx.match?.[1]; 47 | await ctx.reply( 48 | `Select the ${channelOrGroup} you just added the bot to, so as to configure settings of the ${channelOrGroup}.\n\nSettings include:\n- Custom Welcome\n- Auto Approve\n- Auto Disapprove`, 49 | { 50 | reply_markup: new Keyboard().requestChat( 51 | `Select the ${channelOrGroup}`, 52 | 1, 53 | { 54 | chat_is_channel: channelOrGroup == "channel", 55 | bot_is_member: true, 56 | bot_administrator_rights: { 57 | can_invite_users: true, 58 | can_manage_chat: true, 59 | is_anonymous: false, 60 | can_delete_messages: false, 61 | can_restrict_members: false, 62 | can_manage_video_chats: false, 63 | can_promote_members: false, 64 | can_change_info: false, 65 | }, 66 | user_administrator_rights: { 67 | can_invite_users: true, 68 | can_manage_chat: true, 69 | is_anonymous: false, 70 | can_delete_messages: false, 71 | can_restrict_members: false, 72 | can_manage_video_chats: false, 73 | can_promote_members: false, 74 | can_change_info: false, 75 | }, 76 | }, 77 | ) 78 | .row() 79 | .resized() 80 | .oneTime() 81 | .placeholder( 82 | "Choose a chat from the buttons below", 83 | ), 84 | }, 85 | ); 86 | await ctx.deleteMessage(); 87 | }); 88 | 89 | export default composer; 90 | -------------------------------------------------------------------------------- /src/modules/chatSettings.ts: -------------------------------------------------------------------------------- 1 | import { MyContext } from "../core/types.ts"; 2 | import { getSettings, setStatus } from "../database/welcomeDb.ts"; 3 | import { get_perms } from "../helpers/permChecker.ts"; 4 | 5 | import { Composer, InlineKeyboard } from "grammy/mod.ts"; 6 | 7 | const composer = new Composer(); 8 | 9 | async function settingsHandler(ctx: MyContext, chat: number, user: number) { 10 | const res = await get_perms(ctx, chat, user); 11 | if (res == null) { 12 | return await ctx.reply( 13 | ctx.t("no-perms"), 14 | ); 15 | } 16 | if (!res) return await ctx.reply(ctx.t("not-admin")); 17 | const chatInfo = await ctx.api.getChat(chat); 18 | if (chatInfo.type == "private") return; 19 | const current_settings = await getSettings(chat); 20 | let autoappr; 21 | if (current_settings == null) autoappr = true; 22 | else autoappr = current_settings.status ?? true; 23 | const settings_buttons = new InlineKeyboard() 24 | .text(ctx.t("btn-approve"), `approve_${chat}`).row() 25 | .text(ctx.t("btn-disapprove"), `decline_${chat}`).row() 26 | .text(ctx.t("btn-custom"), `welcome_${chat}`); 27 | await ctx.reply( 28 | ctx.t("chat-settings", { 29 | title: chatInfo.title, 30 | autoappr: autoappr.toString(), 31 | }), 32 | { 33 | reply_markup: settings_buttons, 34 | parse_mode: "Markdown", 35 | }, 36 | ); 37 | const tempRemoveKbd = await ctx.reply("Removing keyboard..", { 38 | reply_markup: { remove_keyboard: true }, 39 | }); 40 | await tempRemoveKbd.delete(); 41 | } 42 | composer 43 | .chatType("private") 44 | .filter((ctx) => 45 | !ctx.msg?.text?.startsWith("/") && 46 | ctx.msg?.forward_from_chat?.type == "channel" 47 | ) 48 | .on("message", async (ctx) => { 49 | const chat = ctx.msg?.forward_from_chat?.id; 50 | if (chat == undefined) return; 51 | await settingsHandler(ctx, chat, ctx.from?.id ?? 0); 52 | }); 53 | 54 | composer.on(":chat_shared", async (ctx) => { 55 | const chat = ctx.update.message?.chat_shared.chat_id; 56 | if (chat == undefined) return; 57 | await settingsHandler(ctx, chat, ctx.from?.id ?? 0); 58 | }); 59 | 60 | composer.callbackQuery(/settings_page_(.*)/, async (ctx) => { 61 | const chat = ctx.match?.[1]; 62 | if (chat == undefined) return; 63 | const chatInfo = await ctx.api.getChat(Number(chat)); 64 | if (chatInfo.type == "private") return; 65 | const current_settings = await getSettings(Number(chat)); 66 | let autoappr; 67 | if (current_settings == null) autoappr = true; 68 | else autoappr = current_settings.status ?? true; 69 | const settings_buttons = new InlineKeyboard() 70 | .text(ctx.t("btn-approve"), `approve_${chat}`).row() 71 | .text(ctx.t("btn-disapprove"), `decline_${chat}`).row() 72 | .text(ctx.t("btn-custom"), `welcome_${chat}`); 73 | await ctx.editMessageText( 74 | ctx.t("chat-settings", { 75 | title: chatInfo.title, 76 | autoappr: autoappr.toString(), 77 | }), 78 | { 79 | reply_markup: settings_buttons, 80 | parse_mode: "Markdown", 81 | }, 82 | ); 83 | }); 84 | 85 | composer.callbackQuery(/approve_(.*)/, async (ctx) => { 86 | const chatID = ctx.match?.[1]; 87 | if (chatID == undefined) return; 88 | await setStatus(Number(chatID), true); 89 | const chatInfo = await ctx.api.getChat(Number(chatID)); 90 | if (chatInfo.type == "private") return; 91 | await ctx.editMessageText( 92 | ctx.t("chat-settings-approved", { title: chatInfo.title }), 93 | { 94 | reply_markup: new InlineKeyboard().text( 95 | "« Back", 96 | `settings_page_${chatID}`, 97 | ), 98 | }, 99 | ); 100 | }); 101 | 102 | composer.callbackQuery(/decline_(.*)/, async (ctx) => { 103 | const chatID = ctx.match?.[1]; 104 | if (chatID == undefined) return; 105 | await setStatus(Number(chatID), false); 106 | const chatInfo = await ctx.api.getChat(Number(chatID)); 107 | if (chatInfo.type == "private") return; 108 | await ctx.editMessageText( 109 | ctx.t("chat-settings-disapproved", { title: chatInfo.title }), 110 | { 111 | reply_markup: new InlineKeyboard().text( 112 | "« Back", 113 | `settings_page_${chatID}`, 114 | ), 115 | }, 116 | ); 117 | }); 118 | 119 | composer.callbackQuery(/welcome_(.*)/, async (ctx) => { 120 | await ctx.conversation.enter("inputWelcomeMsg"); 121 | }); 122 | 123 | export default composer; 124 | -------------------------------------------------------------------------------- /src/modules/ownerTools.ts: -------------------------------------------------------------------------------- 1 | import { MyContext } from "../core/types.ts"; 2 | import helperClass from "../helpers/baseHelpers.ts"; 3 | 4 | import { Composer } from "grammy/mod.ts"; 5 | import { countUsers, users } from "../database/usersDb.ts"; 6 | import { getAllSettings } from "../database/welcomeDb.ts"; 7 | 8 | const composer = new Composer(); 9 | 10 | composer 11 | .filter((ctx) => helperClass.OWNERS.includes(ctx.from?.id ?? 0)) 12 | .chatType("private") 13 | .command("stats", async (ctx) => { 14 | const reply = await ctx.reply("Calculating..."); 15 | const diffTime = Math.abs(new Date().valueOf() - helperClass.START_TIME); 16 | let days = diffTime / (24 * 60 * 60 * 1000); 17 | let hours = (days % 1) * 24; 18 | let minutes = (hours % 1) * 60; 19 | let secs = (minutes % 1) * 60; 20 | [days, hours, minutes, secs] = [ 21 | Math.floor(days), 22 | Math.floor(hours), 23 | Math.floor(minutes), 24 | Math.floor(secs), 25 | ]; 26 | let uptime = ""; 27 | if (days > 0) uptime += `${days}d `; 28 | if (hours > 0) uptime += `${hours}h `; 29 | if (minutes > 0) uptime += `${minutes}m `; 30 | if (secs > 0) uptime += `${secs}s.`; 31 | await ctx.api.editMessageText( 32 | ctx.from.id, 33 | reply.message_id, 34 | `Stats for @${(await ctx.api.getMe()).username} 35 | 36 | Total users: ${await countUsers()} 37 | Chats with modified settings: ${(await getAllSettings()).length} 38 | Total Users Seen (Approved/Disapproved): ${helperClass.TOTAL_USERS_SEEN} 39 | Uptime: ${uptime} 40 | 41 | Repository | Channel | Support`, 42 | { parse_mode: "HTML", disable_web_page_preview: true }, 43 | ); 44 | }); 45 | 46 | composer 47 | .filter((ctx) => helperClass.OWNERS.includes(ctx.from?.id ?? 0)) 48 | .chatType("private") 49 | .command("broadcast", async (ctx) => { 50 | if (Deno.env.get("DENO_DEPLOYMENT_ID") != undefined) { 51 | return await ctx.reply( 52 | "This command cannot be used on deno deploy, due to the low CPU response time. Run the bot on a server instead.", 53 | ); 54 | } 55 | const totalUsers = await countUsers(); 56 | let done = 0, blocked = 0; 57 | const reply = await ctx.reply("Please wait, in progress..."); 58 | const isReply = await ctx.message?.reply_to_message; 59 | if (!isReply) { 60 | return await ctx.api.editMessageText( 61 | ctx.chat!.id, 62 | reply.message_id, 63 | "Please reply to a message to broadcast.", 64 | ); 65 | } 66 | 67 | // use curosr to avoid memory issues 68 | // and maybe prevent broadcast from 69 | // blocking the main process 70 | 71 | for await (const { userID } of users.find()) { 72 | const user = userID; 73 | try { 74 | await ctx.api.copyMessage(user, ctx.chat!.id, isReply.message_id, { 75 | reply_markup: isReply.reply_markup, 76 | }); 77 | done++; 78 | } catch (err) { 79 | if (err.parameters.retry_after) { 80 | const timeOut = err.parameters.retry_after; 81 | const wait = Number(timeOut * 2000); 82 | await ctx.api.editMessageText( 83 | ctx.chat!.id, 84 | reply.message_id, 85 | `Seeping for ${timeOut} seconds due to a floodwait.\n\nBroadcast completed to ${done}/${totalUsers} users, of which ${blocked} blocked the bot.`, 86 | ); 87 | await new Promise((f) => setTimeout(f, wait)); 88 | await ctx.api.editMessageText( 89 | ctx.chat!.id, 90 | reply.message_id, 91 | `Restarted broadcast, already sent to ${done}/${totalUsers} users, of which ${blocked} blocked the bot.`, 92 | ); 93 | } 94 | if (err.error_code == 403 || err.error_code == 400) blocked++; 95 | else { 96 | console.log( 97 | `Failed to send message to ${user}. Error: ${err.message}`, 98 | ); 99 | } 100 | } 101 | if (done % 100 == 0) { 102 | await ctx.api.editMessageText( 103 | ctx.chat!.id, 104 | reply.message_id, 105 | `Brodcast done to ${done}/${totalUsers} users, of which ${blocked} blocked the bot.\n\nStill in progress...`, 106 | ); 107 | } 108 | } 109 | await ctx.api.editMessageText( 110 | ctx.chat!.id, 111 | reply.message_id, 112 | `Broadcast completed. 113 | 114 | Total users: ${totalUsers} 115 | Sent to: ${done} 116 | Blocked: ${blocked} 117 | Failed for unknown reason: ${totalUsers - done - blocked}`, 118 | ); 119 | }); 120 | 121 | export default composer; 122 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU Affero General Public License is a free, copyleft license for 11 | software and other kinds of works, specifically designed to ensure 12 | cooperation with the community in the case of network server software. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | our General Public Licenses are intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. 19 | 20 | When we speak of free software, we are referring to freedom, not 21 | price. Our General Public Licenses are designed to make sure that you 22 | have the freedom to distribute copies of free software (and charge for 23 | them if you wish), that you receive source code or can get it if you 24 | want it, that you can change the software or use pieces of it in new 25 | free programs, and that you know you can do these things. 26 | 27 | Developers that use our General Public Licenses protect your rights 28 | with two steps: (1) assert copyright on the software, and (2) offer 29 | you this License which gives you legal permission to copy, distribute 30 | and/or modify the software. 31 | 32 | A secondary benefit of defending all users' freedom is that 33 | improvements made in alternate versions of the program, if they 34 | receive widespread use, become available for other developers to 35 | incorporate. Many developers of free software are heartened and 36 | encouraged by the resulting cooperation. However, in the case of 37 | software used on network servers, this result may fail to come about. 38 | The GNU General Public License permits making a modified version and 39 | letting the public access it on a server without ever releasing its 40 | source code to the public. 41 | 42 | The GNU Affero General Public License is designed specifically to 43 | ensure that, in such cases, the modified source code becomes available 44 | to the community. It requires the operator of a network server to 45 | provide the source code of the modified version running there to the 46 | users of that server. Therefore, public use of a modified version, on 47 | a publicly accessible server, gives the public access to the source 48 | code of the modified version. 49 | 50 | An older license, called the Affero General Public License and 51 | published by Affero, was designed to accomplish similar goals. This is 52 | a different license, not a version of the Affero GPL, but Affero has 53 | released a new version of the Affero GPL which permits relicensing under 54 | this license. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | TERMS AND CONDITIONS 60 | 61 | 0. Definitions. 62 | 63 | "This License" refers to version 3 of the GNU Affero General Public License. 64 | 65 | "Copyright" also means copyright-like laws that apply to other kinds of 66 | works, such as semiconductor masks. 67 | 68 | "The Program" refers to any copyrightable work licensed under this 69 | License. Each licensee is addressed as "you". "Licensees" and 70 | "recipients" may be individuals or organizations. 71 | 72 | To "modify" a work means to copy from or adapt all or part of the work 73 | in a fashion requiring copyright permission, other than the making of an 74 | exact copy. The resulting work is called a "modified version" of the 75 | earlier work or a work "based on" the earlier work. 76 | 77 | A "covered work" means either the unmodified Program or a work based 78 | on the Program. 79 | 80 | To "propagate" a work means to do anything with it that, without 81 | permission, would make you directly or secondarily liable for 82 | infringement under applicable copyright law, except executing it on a 83 | computer or modifying a private copy. Propagation includes copying, 84 | distribution (with or without modification), making available to the 85 | public, and in some countries other activities as well. 86 | 87 | To "convey" a work means any kind of propagation that enables other 88 | parties to make or receive copies. Mere interaction with a user through 89 | a computer network, with no transfer of a copy, is not conveying. 90 | 91 | An interactive user interface displays "Appropriate Legal Notices" 92 | to the extent that it includes a convenient and prominently visible 93 | feature that (1) displays an appropriate copyright notice, and (2) 94 | tells the user that there is no warranty for the work (except to the 95 | extent that warranties are provided), that licensees may convey the 96 | work under this License, and how to view a copy of this License. If 97 | the interface presents a list of user commands or options, such as a 98 | menu, a prominent item in the list meets this criterion. 99 | 100 | 1. Source Code. 101 | 102 | The "source code" for a work means the preferred form of the work 103 | for making modifications to it. "Object code" means any non-source 104 | form of a work. 105 | 106 | A "Standard Interface" means an interface that either is an official 107 | standard defined by a recognized standards body, or, in the case of 108 | interfaces specified for a particular programming language, one that 109 | is widely used among developers working in that language. 110 | 111 | The "System Libraries" of an executable work include anything, other 112 | than the work as a whole, that (a) is included in the normal form of 113 | packaging a Major Component, but which is not part of that Major 114 | Component, and (b) serves only to enable use of the work with that 115 | Major Component, or to implement a Standard Interface for which an 116 | implementation is available to the public in source code form. A 117 | "Major Component", in this context, means a major essential component 118 | (kernel, window system, and so on) of the specific operating system 119 | (if any) on which the executable work runs, or a compiler used to 120 | produce the work, or an object code interpreter used to run it. 121 | 122 | The "Corresponding Source" for a work in object code form means all 123 | the source code needed to generate, install, and (for an executable 124 | work) run the object code and to modify the work, including scripts to 125 | control those activities. However, it does not include the work's 126 | System Libraries, or general-purpose tools or generally available free 127 | programs which are used unmodified in performing those activities but 128 | which are not part of the work. For example, Corresponding Source 129 | includes interface definition files associated with source files for 130 | the work, and the source code for shared libraries and dynamically 131 | linked subprograms that the work is specifically designed to require, 132 | such as by intimate data communication or control flow between those 133 | subprograms and other parts of the work. 134 | 135 | The Corresponding Source need not include anything that users 136 | can regenerate automatically from other parts of the Corresponding 137 | Source. 138 | 139 | The Corresponding Source for a work in source code form is that 140 | same work. 141 | 142 | 2. Basic Permissions. 143 | 144 | All rights granted under this License are granted for the term of 145 | copyright on the Program, and are irrevocable provided the stated 146 | conditions are met. This License explicitly affirms your unlimited 147 | permission to run the unmodified Program. The output from running a 148 | covered work is covered by this License only if the output, given its 149 | content, constitutes a covered work. This License acknowledges your 150 | rights of fair use or other equivalent, as provided by copyright law. 151 | 152 | You may make, run and propagate covered works that you do not 153 | convey, without conditions so long as your license otherwise remains 154 | in force. You may convey covered works to others for the sole purpose 155 | of having them make modifications exclusively for you, or provide you 156 | with facilities for running those works, provided that you comply with 157 | the terms of this License in conveying all material for which you do 158 | not control copyright. Those thus making or running the covered works 159 | for you must do so exclusively on your behalf, under your direction 160 | and control, on terms that prohibit them from making any copies of 161 | your copyrighted material outside their relationship with you. 162 | 163 | Conveying under any other circumstances is permitted solely under 164 | the conditions stated below. Sublicensing is not allowed; section 10 165 | makes it unnecessary. 166 | 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 | 169 | No covered work shall be deemed part of an effective technological 170 | measure under any applicable law fulfilling obligations under article 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 | similar laws prohibiting or restricting circumvention of such 173 | measures. 174 | 175 | When you convey a covered work, you waive any legal power to forbid 176 | circumvention of technological measures to the extent such circumvention 177 | is effected by exercising rights under this License with respect to 178 | the covered work, and you disclaim any intention to limit operation or 179 | modification of the work as a means of enforcing, against the work's 180 | users, your or third parties' legal rights to forbid circumvention of 181 | technological measures. 182 | 183 | 4. Conveying Verbatim Copies. 184 | 185 | You may convey verbatim copies of the Program's source code as you 186 | receive it, in any medium, provided that you conspicuously and 187 | appropriately publish on each copy an appropriate copyright notice; 188 | keep intact all notices stating that this License and any 189 | non-permissive terms added in accord with section 7 apply to the code; 190 | keep intact all notices of the absence of any warranty; and give all 191 | recipients a copy of this License along with the Program. 192 | 193 | You may charge any price or no price for each copy that you convey, 194 | and you may offer support or warranty protection for a fee. 195 | 196 | 5. Conveying Modified Source Versions. 197 | 198 | You may convey a work based on the Program, or the modifications to 199 | produce it from the Program, in the form of source code under the 200 | terms of section 4, provided that you also meet all of these conditions: 201 | 202 | a) The work must carry prominent notices stating that you modified 203 | it, and giving a relevant date. 204 | 205 | b) The work must carry prominent notices stating that it is 206 | released under this License and any conditions added under section 207 | 7. This requirement modifies the requirement in section 4 to 208 | "keep intact all notices". 209 | 210 | c) You must license the entire work, as a whole, under this 211 | License to anyone who comes into possession of a copy. This 212 | License will therefore apply, along with any applicable section 7 213 | additional terms, to the whole of the work, and all its parts, 214 | regardless of how they are packaged. This License gives no 215 | permission to license the work in any other way, but it does not 216 | invalidate such permission if you have separately received it. 217 | 218 | d) If the work has interactive user interfaces, each must display 219 | Appropriate Legal Notices; however, if the Program has interactive 220 | interfaces that do not display Appropriate Legal Notices, your 221 | work need not make them do so. 222 | 223 | A compilation of a covered work with other separate and independent 224 | works, which are not by their nature extensions of the covered work, 225 | and which are not combined with it such as to form a larger program, 226 | in or on a volume of a storage or distribution medium, is called an 227 | "aggregate" if the compilation and its resulting copyright are not 228 | used to limit the access or legal rights of the compilation's users 229 | beyond what the individual works permit. Inclusion of a covered work 230 | in an aggregate does not cause this License to apply to the other 231 | parts of the aggregate. 232 | 233 | 6. Conveying Non-Source Forms. 234 | 235 | You may convey a covered work in object code form under the terms 236 | of sections 4 and 5, provided that you also convey the 237 | machine-readable Corresponding Source under the terms of this License, 238 | in one of these ways: 239 | 240 | a) Convey the object code in, or embodied in, a physical product 241 | (including a physical distribution medium), accompanied by the 242 | Corresponding Source fixed on a durable physical medium 243 | customarily used for software interchange. 244 | 245 | b) Convey the object code in, or embodied in, a physical product 246 | (including a physical distribution medium), accompanied by a 247 | written offer, valid for at least three years and valid for as 248 | long as you offer spare parts or customer support for that product 249 | model, to give anyone who possesses the object code either (1) a 250 | copy of the Corresponding Source for all the software in the 251 | product that is covered by this License, on a durable physical 252 | medium customarily used for software interchange, for a price no 253 | more than your reasonable cost of physically performing this 254 | conveying of source, or (2) access to copy the 255 | Corresponding Source from a network server at no charge. 256 | 257 | c) Convey individual copies of the object code with a copy of the 258 | written offer to provide the Corresponding Source. This 259 | alternative is allowed only occasionally and noncommercially, and 260 | only if you received the object code with such an offer, in accord 261 | with subsection 6b. 262 | 263 | d) Convey the object code by offering access from a designated 264 | place (gratis or for a charge), and offer equivalent access to the 265 | Corresponding Source in the same way through the same place at no 266 | further charge. You need not require recipients to copy the 267 | Corresponding Source along with the object code. If the place to 268 | copy the object code is a network server, the Corresponding Source 269 | may be on a different server (operated by you or a third party) 270 | that supports equivalent copying facilities, provided you maintain 271 | clear directions next to the object code saying where to find the 272 | Corresponding Source. Regardless of what server hosts the 273 | Corresponding Source, you remain obligated to ensure that it is 274 | available for as long as needed to satisfy these requirements. 275 | 276 | e) Convey the object code using peer-to-peer transmission, provided 277 | you inform other peers where the object code and Corresponding 278 | Source of the work are being offered to the general public at no 279 | charge under subsection 6d. 280 | 281 | A separable portion of the object code, whose source code is excluded 282 | from the Corresponding Source as a System Library, need not be 283 | included in conveying the object code work. 284 | 285 | A "User Product" is either (1) a "consumer product", which means any 286 | tangible personal property which is normally used for personal, family, 287 | or household purposes, or (2) anything designed or sold for incorporation 288 | into a dwelling. In determining whether a product is a consumer product, 289 | doubtful cases shall be resolved in favor of coverage. For a particular 290 | product received by a particular user, "normally used" refers to a 291 | typical or common use of that class of product, regardless of the status 292 | of the particular user or of the way in which the particular user 293 | actually uses, or expects or is expected to use, the product. A product 294 | is a consumer product regardless of whether the product has substantial 295 | commercial, industrial or non-consumer uses, unless such uses represent 296 | the only significant mode of use of the product. 297 | 298 | "Installation Information" for a User Product means any methods, 299 | procedures, authorization keys, or other information required to install 300 | and execute modified versions of a covered work in that User Product from 301 | a modified version of its Corresponding Source. The information must 302 | suffice to ensure that the continued functioning of the modified object 303 | code is in no case prevented or interfered with solely because 304 | modification has been made. 305 | 306 | If you convey an object code work under this section in, or with, or 307 | specifically for use in, a User Product, and the conveying occurs as 308 | part of a transaction in which the right of possession and use of the 309 | User Product is transferred to the recipient in perpetuity or for a 310 | fixed term (regardless of how the transaction is characterized), the 311 | Corresponding Source conveyed under this section must be accompanied 312 | by the Installation Information. But this requirement does not apply 313 | if neither you nor any third party retains the ability to install 314 | modified object code on the User Product (for example, the work has 315 | been installed in ROM). 316 | 317 | The requirement to provide Installation Information does not include a 318 | requirement to continue to provide support service, warranty, or updates 319 | for a work that has been modified or installed by the recipient, or for 320 | the User Product in which it has been modified or installed. Access to a 321 | network may be denied when the modification itself materially and 322 | adversely affects the operation of the network or violates the rules and 323 | protocols for communication across the network. 324 | 325 | Corresponding Source conveyed, and Installation Information provided, 326 | in accord with this section must be in a format that is publicly 327 | documented (and with an implementation available to the public in 328 | source code form), and must require no special password or key for 329 | unpacking, reading or copying. 330 | 331 | 7. Additional Terms. 332 | 333 | "Additional permissions" are terms that supplement the terms of this 334 | License by making exceptions from one or more of its conditions. 335 | Additional permissions that are applicable to the entire Program shall 336 | be treated as though they were included in this License, to the extent 337 | that they are valid under applicable law. If additional permissions 338 | apply only to part of the Program, that part may be used separately 339 | under those permissions, but the entire Program remains governed by 340 | this License without regard to the additional permissions. 341 | 342 | When you convey a copy of a covered work, you may at your option 343 | remove any additional permissions from that copy, or from any part of 344 | it. (Additional permissions may be written to require their own 345 | removal in certain cases when you modify the work.) You may place 346 | additional permissions on material, added by you to a covered work, 347 | for which you have or can give appropriate copyright permission. 348 | 349 | Notwithstanding any other provision of this License, for material you 350 | add to a covered work, you may (if authorized by the copyright holders of 351 | that material) supplement the terms of this License with terms: 352 | 353 | a) Disclaiming warranty or limiting liability differently from the 354 | terms of sections 15 and 16 of this License; or 355 | 356 | b) Requiring preservation of specified reasonable legal notices or 357 | author attributions in that material or in the Appropriate Legal 358 | Notices displayed by works containing it; or 359 | 360 | c) Prohibiting misrepresentation of the origin of that material, or 361 | requiring that modified versions of such material be marked in 362 | reasonable ways as different from the original version; or 363 | 364 | d) Limiting the use for publicity purposes of names of licensors or 365 | authors of the material; or 366 | 367 | e) Declining to grant rights under trademark law for use of some 368 | trade names, trademarks, or service marks; or 369 | 370 | f) Requiring indemnification of licensors and authors of that 371 | material by anyone who conveys the material (or modified versions of 372 | it) with contractual assumptions of liability to the recipient, for 373 | any liability that these contractual assumptions directly impose on 374 | those licensors and authors. 375 | 376 | All other non-permissive additional terms are considered "further 377 | restrictions" within the meaning of section 10. If the Program as you 378 | received it, or any part of it, contains a notice stating that it is 379 | governed by this License along with a term that is a further 380 | restriction, you may remove that term. If a license document contains 381 | a further restriction but permits relicensing or conveying under this 382 | License, you may add to a covered work material governed by the terms 383 | of that license document, provided that the further restriction does 384 | not survive such relicensing or conveying. 385 | 386 | If you add terms to a covered work in accord with this section, you 387 | must place, in the relevant source files, a statement of the 388 | additional terms that apply to those files, or a notice indicating 389 | where to find the applicable terms. 390 | 391 | Additional terms, permissive or non-permissive, may be stated in the 392 | form of a separately written license, or stated as exceptions; 393 | the above requirements apply either way. 394 | 395 | 8. Termination. 396 | 397 | You may not propagate or modify a covered work except as expressly 398 | provided under this License. Any attempt otherwise to propagate or 399 | modify it is void, and will automatically terminate your rights under 400 | this License (including any patent licenses granted under the third 401 | paragraph of section 11). 402 | 403 | However, if you cease all violation of this License, then your 404 | license from a particular copyright holder is reinstated (a) 405 | provisionally, unless and until the copyright holder explicitly and 406 | finally terminates your license, and (b) permanently, if the copyright 407 | holder fails to notify you of the violation by some reasonable means 408 | prior to 60 days after the cessation. 409 | 410 | Moreover, your license from a particular copyright holder is 411 | reinstated permanently if the copyright holder notifies you of the 412 | violation by some reasonable means, this is the first time you have 413 | received notice of violation of this License (for any work) from that 414 | copyright holder, and you cure the violation prior to 30 days after 415 | your receipt of the notice. 416 | 417 | Termination of your rights under this section does not terminate the 418 | licenses of parties who have received copies or rights from you under 419 | this License. If your rights have been terminated and not permanently 420 | reinstated, you do not qualify to receive new licenses for the same 421 | material under section 10. 422 | 423 | 9. Acceptance Not Required for Having Copies. 424 | 425 | You are not required to accept this License in order to receive or 426 | run a copy of the Program. Ancillary propagation of a covered work 427 | occurring solely as a consequence of using peer-to-peer transmission 428 | to receive a copy likewise does not require acceptance. However, 429 | nothing other than this License grants you permission to propagate or 430 | modify any covered work. These actions infringe copyright if you do 431 | not accept this License. Therefore, by modifying or propagating a 432 | covered work, you indicate your acceptance of this License to do so. 433 | 434 | 10. Automatic Licensing of Downstream Recipients. 435 | 436 | Each time you convey a covered work, the recipient automatically 437 | receives a license from the original licensors, to run, modify and 438 | propagate that work, subject to this License. You are not responsible 439 | for enforcing compliance by third parties with this License. 440 | 441 | An "entity transaction" is a transaction transferring control of an 442 | organization, or substantially all assets of one, or subdividing an 443 | organization, or merging organizations. If propagation of a covered 444 | work results from an entity transaction, each party to that 445 | transaction who receives a copy of the work also receives whatever 446 | licenses to the work the party's predecessor in interest had or could 447 | give under the previous paragraph, plus a right to possession of the 448 | Corresponding Source of the work from the predecessor in interest, if 449 | the predecessor has it or can get it with reasonable efforts. 450 | 451 | You may not impose any further restrictions on the exercise of the 452 | rights granted or affirmed under this License. For example, you may 453 | not impose a license fee, royalty, or other charge for exercise of 454 | rights granted under this License, and you may not initiate litigation 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that 456 | any patent claim is infringed by making, using, selling, offering for 457 | sale, or importing the Program or any portion of it. 458 | 459 | 11. Patents. 460 | 461 | A "contributor" is a copyright holder who authorizes use under this 462 | License of the Program or a work on which the Program is based. The 463 | work thus licensed is called the contributor's "contributor version". 464 | 465 | A contributor's "essential patent claims" are all patent claims 466 | owned or controlled by the contributor, whether already acquired or 467 | hereafter acquired, that would be infringed by some manner, permitted 468 | by this License, of making, using, or selling its contributor version, 469 | but do not include claims that would be infringed only as a 470 | consequence of further modification of the contributor version. For 471 | purposes of this definition, "control" includes the right to grant 472 | patent sublicenses in a manner consistent with the requirements of 473 | this License. 474 | 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free 476 | patent license under the contributor's essential patent claims, to 477 | make, use, sell, offer for sale, import and otherwise run, modify and 478 | propagate the contents of its contributor version. 479 | 480 | In the following three paragraphs, a "patent license" is any express 481 | agreement or commitment, however denominated, not to enforce a patent 482 | (such as an express permission to practice a patent or covenant not to 483 | sue for patent infringement). To "grant" such a patent license to a 484 | party means to make such an agreement or commitment not to enforce a 485 | patent against the party. 486 | 487 | If you convey a covered work, knowingly relying on a patent license, 488 | and the Corresponding Source of the work is not available for anyone 489 | to copy, free of charge and under the terms of this License, through a 490 | publicly available network server or other readily accessible means, 491 | then you must either (1) cause the Corresponding Source to be so 492 | available, or (2) arrange to deprive yourself of the benefit of the 493 | patent license for this particular work, or (3) arrange, in a manner 494 | consistent with the requirements of this License, to extend the patent 495 | license to downstream recipients. "Knowingly relying" means you have 496 | actual knowledge that, but for the patent license, your conveying the 497 | covered work in a country, or your recipient's use of the covered work 498 | in a country, would infringe one or more identifiable patents in that 499 | country that you have reason to believe are valid. 500 | 501 | If, pursuant to or in connection with a single transaction or 502 | arrangement, you convey, or propagate by procuring conveyance of, a 503 | covered work, and grant a patent license to some of the parties 504 | receiving the covered work authorizing them to use, propagate, modify 505 | or convey a specific copy of the covered work, then the patent license 506 | you grant is automatically extended to all recipients of the covered 507 | work and works based on it. 508 | 509 | A patent license is "discriminatory" if it does not include within 510 | the scope of its coverage, prohibits the exercise of, or is 511 | conditioned on the non-exercise of one or more of the rights that are 512 | specifically granted under this License. You may not convey a covered 513 | work if you are a party to an arrangement with a third party that is 514 | in the business of distributing software, under which you make payment 515 | to the third party based on the extent of your activity of conveying 516 | the work, and under which the third party grants, to any of the 517 | parties who would receive the covered work from you, a discriminatory 518 | patent license (a) in connection with copies of the covered work 519 | conveyed by you (or copies made from those copies), or (b) primarily 520 | for and in connection with specific products or compilations that 521 | contain the covered work, unless you entered into that arrangement, 522 | or that patent license was granted, prior to 28 March 2007. 523 | 524 | Nothing in this License shall be construed as excluding or limiting 525 | any implied license or other defenses to infringement that may 526 | otherwise be available to you under applicable patent law. 527 | 528 | 12. No Surrender of Others' Freedom. 529 | 530 | If conditions are imposed on you (whether by court order, agreement or 531 | otherwise) that contradict the conditions of this License, they do not 532 | excuse you from the conditions of this License. If you cannot convey a 533 | covered work so as to satisfy simultaneously your obligations under this 534 | License and any other pertinent obligations, then as a consequence you may 535 | not convey it at all. For example, if you agree to terms that obligate you 536 | to collect a royalty for further conveying from those to whom you convey 537 | the Program, the only way you could satisfy both those terms and this 538 | License would be to refrain entirely from conveying the Program. 539 | 540 | 13. Remote Network Interaction; Use with the GNU General Public License. 541 | 542 | Notwithstanding any other provision of this License, if you modify the 543 | Program, your modified version must prominently offer all users 544 | interacting with it remotely through a computer network (if your version 545 | supports such interaction) an opportunity to receive the Corresponding 546 | Source of your version by providing access to the Corresponding Source 547 | from a network server at no charge, through some standard or customary 548 | means of facilitating copying of software. This Corresponding Source 549 | shall include the Corresponding Source for any work covered by version 3 550 | of the GNU General Public License that is incorporated pursuant to the 551 | following paragraph. 552 | 553 | Notwithstanding any other provision of this License, you have 554 | permission to link or combine any covered work with a work licensed 555 | under version 3 of the GNU General Public License into a single 556 | combined work, and to convey the resulting work. The terms of this 557 | License will continue to apply to the part which is the covered work, 558 | but the work with which it is combined will remain governed by version 559 | 3 of the GNU General Public License. 560 | 561 | 14. Revised Versions of this License. 562 | 563 | The Free Software Foundation may publish revised and/or new versions of 564 | the GNU Affero General Public License from time to time. Such new versions 565 | will be similar in spirit to the present version, but may differ in detail to 566 | address new problems or concerns. 567 | 568 | Each version is given a distinguishing version number. If the 569 | Program specifies that a certain numbered version of the GNU Affero General 570 | Public License "or any later version" applies to it, you have the 571 | option of following the terms and conditions either of that numbered 572 | version or of any later version published by the Free Software 573 | Foundation. If the Program does not specify a version number of the 574 | GNU Affero General Public License, you may choose any version ever published 575 | by the Free Software Foundation. 576 | 577 | If the Program specifies that a proxy can decide which future 578 | versions of the GNU Affero General Public License can be used, that proxy's 579 | public statement of acceptance of a version permanently authorizes you 580 | to choose that version for the Program. 581 | 582 | Later license versions may give you additional or different 583 | permissions. However, no additional obligations are imposed on any 584 | author or copyright holder as a result of your choosing to follow a 585 | later version. 586 | 587 | 15. Disclaimer of Warranty. 588 | 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 | 598 | 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 | SUCH DAMAGES. 609 | 610 | 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these terms. 626 | 627 | To do so, attach the following notices to the program. It is safest 628 | to attach them to the start of each source file to most effectively 629 | state the exclusion of warranty; and each file should have at least 630 | the "copyright" line and a pointer to where the full notice is found. 631 | 632 | 633 | Copyright (C) 634 | 635 | This program is free software: you can redistribute it and/or modify 636 | it under the terms of the GNU Affero General Public License as published by 637 | the Free Software Foundation, either version 3 of the License, or 638 | (at your option) any later version. 639 | 640 | This program is distributed in the hope that it will be useful, 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 | GNU Affero General Public License for more details. 644 | 645 | You should have received a copy of the GNU Affero General Public License 646 | along with this program. If not, see . 647 | 648 | Also add information on how to contact you by electronic and paper mail. 649 | 650 | If your software can interact with users remotely through a computer 651 | network, you should also make sure that it provides a way for users to 652 | get its source. For example, if your program is a web application, its 653 | interface could display a "Source" link that leads users to an archive 654 | of the code. There are many ways you could offer source, and different 655 | solutions will be better for different programs; see section 13 for the 656 | specific requirements. 657 | 658 | You should also get your employer (if you work as a programmer) or school, 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. 660 | For more information on this, and how to apply and follow the GNU AGPL, see 661 | . 662 | --------------------------------------------------------------------------------