Skip to content

Commit 7a23fe2

Browse files
committed
chore: add code
1 parent e5ff892 commit 7a23fe2

26 files changed

+815
-0
lines changed

locales/ru.js

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
module.exports = {
2+
translation: {
3+
keyboard: {
4+
main: {},
5+
back: '◀️ Назад'
6+
},
7+
src: {
8+
originTooLong: 'Увы, оригинальное сообщение слишком длинное'
9+
},
10+
getId: {
11+
text: '<b>Тип идентификатора:</b> <code>{{ type }}</code>{{- anonymous }}\n' + // "-" disables escape for variable
12+
'<b>Идентификатор:</b> <code>{{ id }}</code>',
13+
anonymous: '(анонимный администратор <code>{{ name }}</code>)',
14+
inlineTitle: 'Ваш ID {{ id }}',
15+
inlineDescription: 'Нажмите, чтобы отправит его в текущий чат',
16+
inlineContent: 'Мой Telegram ID {{ id }}'
17+
},
18+
reference: {
19+
openButton: '🔗 Bots API Reference',
20+
botsApiTitle: 'Telegram Bot API Reference {{ version }} ({{ date }})',
21+
botsApiDescription: 'The Bot API is an HTTP-based interface created for developers keen on building bots for Telegram.',
22+
botsApiContent: '<a href="https://core.telegram.org/bots/api">Telegram Bot API Reference</a>',
23+
methodContent: '*Method:* `{{ name }}`:\n\n' +
24+
'{{- description }}\n' +
25+
'*Arguments:*\n' +
26+
'{{- arguments }}',
27+
typeContent: '*Type:* `{{ name }}`:\n\n' +
28+
'{{- description }}\n\n' +
29+
'*Properties:*\n' +
30+
'{{- properties }}',
31+
opengramTitle: 'Opengram API Reference',
32+
opengramDescription: 'Нажмите для отправки в текущий чат',
33+
opengramContent: '<a href="https://reference.opengram.dev">Opengram API Reference</a>'
34+
},
35+
unmatched: {
36+
message: '<b>Главное меню</b>'
37+
}
38+
}
39+
}

src/components/user/user.model.js

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
const { Schema, model } = require('mongoose')
2+
3+
const user = new Schema({
4+
user: {
5+
name: {
6+
type: String,
7+
required: false
8+
},
9+
nameLower: {
10+
type: String,
11+
required: false
12+
},
13+
first: {
14+
type: String,
15+
required: true
16+
},
17+
last: {
18+
type: String,
19+
required: false
20+
}
21+
},
22+
userId: {
23+
type: Number,
24+
required: true,
25+
index: {
26+
unique: true
27+
}
28+
}
29+
}, {
30+
timestamps: true,
31+
autoCreate: true,
32+
autoIndex: true
33+
})
34+
35+
user.index({ 'user.name': 1 }, {
36+
unique: true,
37+
partialFilterExpression: {
38+
'user.name': {
39+
$exists: true
40+
}
41+
}
42+
})
43+
44+
user.index({ 'user.nameLower': 1 }, {
45+
unique: true,
46+
partialFilterExpression: {
47+
'user.name': {
48+
$exists: true
49+
}
50+
}
51+
})
52+
53+
module.exports = { User: model('user', user) }

src/config.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const { BOT_TOKEN, MONGODB_URI } = process.env
2+
3+
module.exports = {
4+
BOT_TOKEN,
5+
MONGODB_URI,
6+
isProduction: process.env.NODE_ENV && process.env.NODE_ENV !== 'development'
7+
}

src/index.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
require('dotenv').config()
2+
require('./lib/database')
3+
require('./lib/bot')()

src/keyboards/index.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const { mainKeyboard } = require('./main.keyboard')
2+
3+
module.exports = {
4+
mainKeyboard
5+
}

src/keyboards/main.keyboard.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
const { Extra, Markup } = require('opengram')
2+
3+
const mainKeyboard = function createMainKeyboard (ctx) {
4+
return Extra.markup(m => {
5+
return m.keyboard([
6+
Markup.button(ctx.i18n.t('keyboard.main.createStickers')),
7+
Markup.button(ctx.i18n.t('keyboard.main.back'))
8+
], { columns: 1 })
9+
.resize()
10+
})
11+
}
12+
13+
module.exports = { mainKeyboard }

src/lib/bot.js

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
const { Opengram, session } = require('opengram')
2+
const { MediaGroup } = require('@opengram/media-group')
3+
const { BOT_TOKEN } = require('../config')
4+
const { handlers } = require('../middlewares/handlers')
5+
const { logger } = require('./logger')
6+
const { stage } = require('../middlewares/stage')
7+
const { authorization } = require('../middlewares/authorization')
8+
const { StickerSet, User } = require('./models')
9+
const { i18nFactory } = require('../middlewares/i18n')
10+
const i18next = require('i18next')
11+
const fetch = require('node-fetch')
12+
const { sha1 } = require('./utils')
13+
14+
const bot = new Opengram(BOT_TOKEN)
15+
16+
bot.context.model = {
17+
User,
18+
StickerSet
19+
}
20+
21+
async function startBot () {
22+
bot.context.loadBotsAPIReference = async function () {
23+
const data = await fetch('https://ark0f.github.io/tg-bot-api/custom.json')
24+
.then(x => x.json())
25+
26+
data.objects.forEach((v, i) => {
27+
data.objects[i].__object = true
28+
data.objects[i].id = sha1([v.name, 'type'].join())
29+
})
30+
31+
data.methods.forEach((v, i) => {
32+
data.methods[i].__method = true
33+
data.methods[i].id = sha1([v.name, 'method'].join())
34+
})
35+
36+
bot.context.botsAPIReference = data
37+
}
38+
39+
await bot.context.loadBotsAPIReference()
40+
41+
await i18next.init({
42+
lng: 'ru',
43+
fallbackLng: 'ru',
44+
debug: true,
45+
resources: {
46+
ru: require('../../locales/ru')
47+
}
48+
})
49+
50+
bot.use(
51+
new MediaGroup(),
52+
session({
53+
/**
54+
* Session key generator
55+
*
56+
* @param {OpengramContext} ctx Context
57+
* @return {null|string}
58+
*/
59+
getSessionKey: (ctx) => {
60+
if (ctx.from.id && ctx.chat?.id) {
61+
return `${ctx.from.id}:${ctx.chat.id}`
62+
}
63+
64+
if (ctx.inlineQuery || ctx.callbackQuery?.inline_message_id) {
65+
return `${ctx.from.id}:${ctx.from.id}`
66+
}
67+
68+
return null
69+
}
70+
}),
71+
i18nFactory(i18next),
72+
authorization,
73+
stage,
74+
handlers
75+
)
76+
77+
bot.catch(err => logger.error('Bot error:', err))
78+
79+
return bot.launch({
80+
polling: {
81+
allowedUpdates: ['callback_query', 'message', 'inline_query']
82+
}
83+
})
84+
.then(() => logger.info('Bot started successfully'))
85+
}
86+
87+
module.exports = startBot

src/lib/database.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const mongoose = require('mongoose')
2+
const { logger } = require('./logger')
3+
const { MONGODB_URI } = require('../config')
4+
5+
mongoose.connection
6+
.on('open', () => logger.info('Database connection: open'))
7+
.on('close', () => logger.info('Database connection: close'))
8+
.on('disconnected', () => logger.warn('Database connection: disconnecting'))
9+
.on('reconnectFailed', () => logger.error('Database connection: reconnect failed'))
10+
.on('reconnected', () => logger.info('Database connection: reconnected'))
11+
.on('fullsetup', () => logger.info('Database connection: fullsetup'))
12+
.on('all', () => logger.info('Database connection: all'))
13+
.on('error', error => logger.error('MongoDB connection: error', error))
14+
15+
mongoose.connect(MONGODB_URI)

src/lib/logger.js

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
const winston = require('winston')
2+
const { format, transports } = require('winston')
3+
const { isProduction } = require('../config')
4+
5+
const logger = winston.createLogger({ level: 'info' })
6+
7+
if (!isProduction) {
8+
logger.add(
9+
new transports.Console({
10+
format: format.combine(
11+
format.errors({ stack: true }),
12+
format.colorize({ all: true }),
13+
format.label({ label: '[LOGGER]' }),
14+
format.timestamp({ format: 'YY-MM-DD HH:MM:SS' }),
15+
format.prettyPrint(),
16+
winston.format.printf(
17+
({ level, message, label, timestamp, stack }) => {
18+
return ` ${label} ${timestamp} [${level}]: ${message}` + (stack ? '\n' + stack : '')
19+
}
20+
)
21+
)
22+
})
23+
)
24+
} else {
25+
logger.add(
26+
new transports.File({
27+
filename: 'error.log',
28+
level: 'error'
29+
})
30+
)
31+
logger.add(
32+
new transports.File({ filename: 'combined.log' })
33+
)
34+
}
35+
36+
module.exports = { logger }

src/lib/models.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const { User } = require('../components/user/user.model')
2+
3+
module.exports = { User }
+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
class T {
2+
constructor () {
3+
this.types = {
4+
undefined: '*',
5+
properties: 'object',
6+
any_of: 'any_of',
7+
string: 'string',
8+
integer: 'number',
9+
reference: 'reference',
10+
bool: 'boolean',
11+
array: 'Array',
12+
float: 'number'
13+
}
14+
15+
this.references = new Set()
16+
}
17+
18+
enumerate (data) {
19+
const { enumeration, type } = data
20+
if (enumeration === undefined) return type
21+
22+
return enumeration.map(x => `'${x}'`)
23+
.join('|')
24+
}
25+
26+
resolveArrayType ({ array }) {
27+
return `${
28+
this.getType(array)
29+
}[]`
30+
}
31+
32+
getType (data) {
33+
const {
34+
type,
35+
reference
36+
} = data
37+
38+
const resType = this.types[type]
39+
40+
if (resType === 'any_of') {
41+
return data.any_of.map(x => this.getType(x))
42+
.join('|')
43+
}
44+
45+
if (type === 'array') return this.resolveArrayType(data)
46+
if (type === 'string') return this.enumerate(data)
47+
48+
if (resType === 'reference') {
49+
this.references.add(reference)
50+
}
51+
52+
return resType === 'reference' ? reference : resType
53+
}
54+
}
55+
56+
module.exports = { T }

0 commit comments

Comments
 (0)