29 Commits

Author SHA1 Message Date
61c0f095f4 Update libs.versions.toml 2023-08-24 09:43:49 +06:00
309a0dba28 update dependencies 2023-06-09 14:02:45 +06:00
e2c91c5c25 Update libs.versions.toml 2023-05-21 21:37:08 +06:00
b9c6d5a063 fixes in build scripts and config jsons 2023-05-11 01:50:12 +06:00
cfb8ce8b91 make deploy scripts executable 2023-05-11 01:43:57 +06:00
d483219608 update dockerfile and docker-compose 2023-05-11 01:42:38 +06:00
8cbb87178c rename docker-compose service in runner 2023-05-11 01:41:18 +06:00
d1c2dd079f add runner sample 2023-05-11 01:25:11 +06:00
1cc7441e54 actualization 2023-04-27 12:11:39 +06:00
bb78065053 Update libs.versions.toml 2023-01-01 22:57:12 +06:00
af8108cd56 update dependencies 2022-12-27 18:46:13 +06:00
5646b2f581 update fixes 2022-12-08 21:35:06 +06:00
7ae5a158bb Update build.gradle 2022-12-08 11:36:31 +06:00
734b6e51cb Update build.gradle 2022-12-08 11:36:03 +06:00
b655ca5604 Update build.gradle 2022-12-08 11:35:43 +06:00
aa3ed0ed23 Update build.gradle 2022-12-08 11:32:16 +06:00
eabefdbff8 Update libs.versions.toml 2022-12-08 11:29:53 +06:00
24057d5d80 Update libs.versions.toml 2022-11-10 20:40:44 +06:00
15551e4dd2 Merge pull request #1 from InsanusMokrassar/part/welcome
WelcomePlugin
2022-09-22 21:36:35 +06:00
1e6a882896 Merge branch 'master' into part/welcome 2022-09-22 21:36:21 +06:00
eea5fcc360 fixes and improvements 2022-09-22 16:06:21 +06:00
7483988faa remove handling of welcome message sending errors 2022-09-22 15:24:53 +06:00
2ba35e7b9b replace unset of welcome message by logging of errors on welcome sending 2022-09-22 15:24:07 +06:00
8634007e06 small import fixes 2022-09-22 15:13:27 +06:00
0f77475434 add admins cache api usage 2022-09-22 15:00:40 +06:00
6cefafbd09 remove redundant imports in WelcomePlugin 2022-09-22 14:30:01 +06:00
05ddfadb03 update dependencies 2022-09-22 14:29:09 +06:00
c951f074ae updates 2022-09-22 14:28:49 +06:00
34ee7875ed Update gradle-wrapper.properties 2022-07-23 00:04:57 +06:00
21 changed files with 271 additions and 71 deletions

View File

@@ -0,0 +1,5 @@
{
"module_name": "Sample",
"module_package": "{{.module_name.lowercase()}}",
"module_path": "{{.module_package.replace('.', '/')}}"
}

View File

@@ -0,0 +1,27 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath libs.kotlin.gradle.plugin
classpath libs.kotlin.serialization.plugin
}
}
plugins {
alias libs.plugins.kotlin.jvm
alias libs.plugins.kotlin.serialization
}
repositories {
mavenCentral()
mavenLocal()
maven { url "https://git.inmo.dev/api/packages/InsanusMokrassar/maven" }
}
dependencies {
implementation libs.kotlin
api libs.plagubot.plugin
api libs.kslog
}

View File

@@ -0,0 +1,60 @@
import dev.inmo.kslog.common.logger
import dev.inmo.kslog.common.w
import dev.inmo.plagubot.Plugin
import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.api.send.sendMessage
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMyChatMemberUpdated
import dev.inmo.tgbotapi.types.chat.PrivateChat
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.*
import org.jetbrains.exposed.sql.Database
import org.koin.core.Koin
import org.koin.core.module.Module
/**
* This is template of plugin with preset [log]ger, [Config] and template configurations of [setupDI] and [setupBotPlugin].
* Replace [pluginConfigSectionName] value with your one to customize configuration section name
*/
@Serializable
class {{.module_name}}Plugin : Plugin {
/**
* Default logger of [WelcomePlugin] got with [logger]
*/
private val log = logger
/**
* Configuration class for current plugin
*
* See realization of [setupDI] to get know how this class will be deserialized from global config
*
* See realization of [setupBotPlugin] to get know how to get access to this class
*/
@Serializable
private class Config(
)
/**
* DI configuration of current plugin. Here we are decoding [Config] and put it into [Module] receiver
*/
override fun Module.setupDI(database: Database, params: JsonObject) {
single { get<Json>().decodeFromJsonElement(Config.serializer(), params[pluginConfigSectionName] ?: return@single null) }
}
/**
* Final configuration of bot. Here we are getting [Config] from [koin]
*/
override suspend fun BehaviourContext.setupBotPlugin(koin: Koin) {
val config = koin.getOrNull<Config>()
if (config == null) {
log.w("Plugin has been disabled due to absence of \"$pluginConfigSectionName\" field in config or some error during configuration loading")
return
}
}
companion object {
private const val pluginConfigSectionName = "new"
}
}

View File

@@ -18,6 +18,7 @@ plugins {
repositories {
mavenCentral()
mavenLocal()
maven { url "https://git.inmo.dev/api/packages/InsanusMokrassar/maven" }
}
dependencies {

View File

@@ -2,6 +2,7 @@
"botToken": "1234567890:ABCDEFGHIJKLMNOP_qrstuvwxyz12345678",
"plugins": [
"dev.inmo.plagubot.plugins.commands.CommandsPlugin",
"dev.inmo.tgbotapi.libraries.cache.admins.AdminsPlugin",
"IntroductionPlugin",
"WelcomePlugin"

View File

@@ -1,9 +1,10 @@
[versions]
kotlin = "1.7.10"
plagubot = "2.2.0"
kslog = "0.5.1"
plagubot-commands = "0.3.2"
kotlin = "1.8.22"
plagubot = "7.1.0"
kslog = "1.1.2"
plagubot-commands = "0.14.0"
tgbotapi-libraries = "0.14.0"
[libraries]
@@ -11,6 +12,7 @@ kotlin = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin"
plagubot = { module = "dev.inmo:plagubot.bot", version.ref = "plagubot" }
plagubot-plugin = { module = "dev.inmo:plagubot.plugin", version.ref = "plagubot" }
plagubot-commands = { module = "dev.inmo:plagubot.plugins.commands", version.ref = "plagubot-commands" }
tgbotapi-libraries-admins = { module = "dev.inmo:tgbotapi.libraries.cache.admins.plagubot", version.ref = "tgbotapi-libraries" }
kslog = { module = "dev.inmo:kslog", version.ref = "kslog" }
# Libs for classpath

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -17,6 +17,7 @@ plugins {
repositories {
mavenCentral()
mavenLocal()
maven { url "https://git.inmo.dev/api/packages/InsanusMokrassar/maven" }
}
dependencies {

7
runner/Dockerfile Normal file
View File

@@ -0,0 +1,7 @@
FROM adoptopenjdk/openjdk11
USER 1000
ENTRYPOINT ["/runner/bin/runner", "/runner/config.json"]
ADD ./build/distributions/runner.tar /

32
runner/build.gradle Normal file
View File

@@ -0,0 +1,32 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath libs.kotlin.gradle.plugin
classpath libs.kotlin.serialization.plugin
}
}
plugins {
alias libs.plugins.kotlin.jvm
alias libs.plugins.kotlin.serialization
id 'application'
}
application.mainClassName = 'dev.inmo.plagubot.AppKt'
repositories {
mavenCentral()
mavenLocal()
maven { url "https://git.inmo.dev/api/packages/InsanusMokrassar/maven" }
}
dependencies {
implementation libs.kotlin
implementation libs.plagubot
implementation project(":introduction")
implementation project(":welcome")
}

16
runner/config.json Normal file
View File

@@ -0,0 +1,16 @@
{
"botToken": "1234567890:ABCDEFGHIJKLMNOP_qrstuvwxyz12345678",
"plugins": [
"dev.inmo.plagubot.plugins.commands.CommandsPlugin",
"dev.inmo.tgbotapi.libraries.cache.admins.AdminsPlugin",
"IntroductionPlugin",
"WelcomePlugin"
],
"introduction": {
"onStartCommandMessage": "Hello World"
},
"database": {
"url": "jdbc:sqlite:file:/data/local.db"
}
}

25
runner/deploy Executable file
View File

@@ -0,0 +1,25 @@
#!/bin/bash
function send_notification() {
echo "$1"
}
function assert_success() {
"${@}"
local status=${?}
if [ ${status} -ne 0 ]; then
send_notification "### Error ${status} at: ${BASH_LINENO[*]} ###"
exit ${status}
fi
}
app=runner
version=0.0.0
server="$USER"
assert_success ../gradlew build
assert_success sudo docker build -t $app:"$version" .
assert_success sudo docker tag $app:"$version" $server/$app:$version
assert_success sudo docker tag $app:"$version" $server/$app:latest
assert_success sudo docker push $server/$app:$version
assert_success sudo docker push $server/$app:latest

10
runner/docker-compose.yml Normal file
View File

@@ -0,0 +1,10 @@
version: "3.4"
services:
runner:
image: user/runner
container_name: runner
restart: unless-stopped
volumes:
- "./data/:/data/"
- "./config.json:/runner/config.json:ro"

25
runner/nonsudo_deploy Executable file
View File

@@ -0,0 +1,25 @@
#!/bin/bash
function send_notification() {
echo "$1"
}
function assert_success() {
"${@}"
local status=${?}
if [ ${status} -ne 0 ]; then
send_notification "### Error ${status} at: ${BASH_LINENO[*]} ###"
exit ${status}
fi
}
app=runner
version=0.0.0
server="$USER"
assert_success ../gradlew build
assert_success docker build -t $app:"$version" .
assert_success docker tag $app:"$version" $server/$app:$version
assert_success docker tag $app:"$version" $server/$app:latest
assert_success docker push $server/$app:$version
assert_success docker push $server/$app:latest

View File

@@ -2,3 +2,4 @@ rootProject.name = "tutorial"
include ":introduction"
include ":welcome"
include ":runner"

View File

@@ -17,6 +17,7 @@ plugins {
repositories {
mavenCentral()
mavenLocal()
maven { url "https://git.inmo.dev/api/packages/InsanusMokrassar/maven" }
}
dependencies {

View File

@@ -17,6 +17,7 @@ plugins {
repositories {
mavenCentral()
mavenLocal()
maven { url "https://git.inmo.dev/api/packages/InsanusMokrassar/maven" }
}
dependencies {
@@ -24,4 +25,5 @@ dependencies {
api libs.plagubot.plugin
api libs.kslog
api libs.plagubot.commands
api libs.tgbotapi.libraries.admins
}

View File

@@ -1,11 +0,0 @@
import dev.inmo.tgbotapi.bot.TelegramBot
import dev.inmo.tgbotapi.extensions.api.chat.get.getChatAdministrators
import dev.inmo.tgbotapi.types.chat.GroupChat
import dev.inmo.tgbotapi.types.chat.User
suspend fun TelegramBot.userIsAdmin(user: User, chat: GroupChat): Boolean {
val chatAdmins = getChatAdministrators(chat)
val chatAdminsIds = chatAdmins.map { adminMember -> adminMember.user.id }
return user.id in chatAdminsIds
}

View File

@@ -1,36 +1,39 @@
import db.WelcomeTable
import dev.inmo.kslog.common.e
import dev.inmo.kslog.common.logger
import dev.inmo.kslog.common.w
import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
import dev.inmo.plagubot.Plugin
import dev.inmo.plagubot.plugins.commands.full
import dev.inmo.tgbotapi.bot.exceptions.RequestException
import dev.inmo.tgbotapi.extensions.api.answers.answer
import dev.inmo.tgbotapi.extensions.api.chat.get.getChatAdministrators
import dev.inmo.tgbotapi.extensions.api.delete
import dev.inmo.tgbotapi.extensions.api.edit.edit
import dev.inmo.tgbotapi.extensions.api.send.*
import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.api.send.send
import dev.inmo.tgbotapi.extensions.behaviour_builder.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitAnyContentMessage
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitContentMessage
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.waitMessageDataCallbackQuery
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.*
import dev.inmo.tgbotapi.extensions.utils.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onNewChatMembers
import dev.inmo.tgbotapi.extensions.utils.extensions.sameChat
import dev.inmo.tgbotapi.extensions.utils.extensions.sameMessage
import dev.inmo.tgbotapi.extensions.utils.formatting.*
import dev.inmo.tgbotapi.extensions.utils.types.buttons.*
import dev.inmo.tgbotapi.extensions.utils.ifCommonGroupContentMessage
import dev.inmo.tgbotapi.extensions.utils.types.buttons.dataButton
import dev.inmo.tgbotapi.extensions.utils.types.buttons.flatInlineKeyboard
import dev.inmo.tgbotapi.libraries.cache.admins.AdminsCacheAPI
import dev.inmo.tgbotapi.types.BotCommand
import dev.inmo.tgbotapi.types.MilliSeconds
import dev.inmo.tgbotapi.types.chat.GroupChat
import dev.inmo.tgbotapi.types.commands.BotCommandScope
import dev.inmo.tgbotapi.types.message.abstracts.CommonGroupContentMessage
import dev.inmo.tgbotapi.types.message.content.MessageContent
import dev.inmo.tgbotapi.types.message.content.TextContent
import dev.inmo.tgbotapi.utils.*
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.*
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import model.ChatSettings
import org.jetbrains.exposed.sql.Database
import org.koin.core.Koin
@@ -72,24 +75,27 @@ class WelcomePlugin : Plugin {
}
private suspend fun BehaviourContext.handleWelcomeCommand(
adminsCacheAPI: AdminsCacheAPI,
welcomeTable: WelcomeTable,
config: Config,
groupMessage: CommonGroupContentMessage<MessageContent>
) {
val user = groupMessage.user
if (userIsAdmin(user, groupMessage.chat)) {
val sentMessage = sendMessage(
if (adminsCacheAPI.isAdmin(groupMessage.chat.id, user.id)) {
val previousMessage = welcomeTable.get(groupMessage.chat.id)
val sentMessage = send(
user,
buildEntities {
regular("Ok, send me the message which should be used as welcome message for chat ")
underline(groupMessage.chat.title)
},
replyMarkup = flatInlineKeyboard {
dataButton("Unset", unsetData)
if (previousMessage != null) {
dataButton("Unset", unsetData)
}
dataButton("Cancel", cancelData)
}
)
) {
regular("Ok, send me the message which should be used as welcome message for chat ")
underline(groupMessage.chat.title)
}
oneOf(
parallel {
@@ -97,7 +103,7 @@ class WelcomePlugin : Plugin {
it.data == unsetData && it.message.sameMessage(sentMessage)
}.first()
val answerEntities = buildEntities {
edit(sentMessage) {
if (welcomeTable.unset(groupMessage.chat.id)) {
regular("Welcome message has been removed for chat ")
underline(groupMessage.chat.title)
@@ -107,11 +113,6 @@ class WelcomePlugin : Plugin {
}
}
edit(
sentMessage,
answerEntities
)
answer(query)
},
parallel {
@@ -119,18 +120,15 @@ class WelcomePlugin : Plugin {
it.data == cancelData && it.message.sameMessage(sentMessage)
}.first()
edit(
sentMessage,
buildEntities {
regular("You have cancelled change of welcome message for chat ")
underline(groupMessage.chat.title)
}
)
edit(sentMessage) {
regular("You have cancelled change of welcome message for chat ")
underline(groupMessage.chat.title)
}
answer(query)
},
parallel {
val message = waitContentMessage().filter {
val message = waitAnyContentMessage().filter {
it.sameChat(sentMessage)
}.first()
@@ -142,7 +140,7 @@ class WelcomePlugin : Plugin {
)
)
val entities = buildEntities {
reply(message) {
if (success) {
regular("Welcome message has been changed for chat ")
underline(groupMessage.chat.title)
@@ -153,17 +151,14 @@ class WelcomePlugin : Plugin {
underline(groupMessage.chat.title)
}
}
reply(
message,
entities
)
delete(sentMessage)
},
parallel {
while (isActive) {
delay(config.recheckOfAdmin)
if (!userIsAdmin(user, groupMessage.chat)) {
edit(sentMessage, "Sorry, but you are not admin in chat ${groupMessage.chat.title} more")
if (adminsCacheAPI.isAdmin(groupMessage.chat.id, user.id)) {
edit(sentMessage, "Sorry, but you are not admin in chat ${groupMessage.chat.title} anymore")
break
}
}
@@ -179,14 +174,15 @@ class WelcomePlugin : Plugin {
val config = koin.get<Config>()
val welcomeTable = koin.get<WelcomeTable>()
val adminsCacheAPI = koin.get<AdminsCacheAPI>()
onCommand(
"welcome",
initialFilter = { it.chat is GroupChat }
) {
it.whenCommonGroupContentMessage { groupMessage ->
it.ifCommonGroupContentMessage { groupMessage ->
launch {
handleWelcomeCommand(welcomeTable, config, groupMessage)
handleWelcomeCommand(adminsCacheAPI, welcomeTable, config, groupMessage)
}
}
}
@@ -198,15 +194,11 @@ class WelcomePlugin : Plugin {
return@onNewChatMembers
}
try {
reply(
it,
chatSettings.sourceChatId,
chatSettings.sourceMessageId
)
} catch (e: RequestException) {
welcomeTable.unset(it.chat.id)
}
reply(
it,
chatSettings.sourceChatId,
chatSettings.sourceMessageId
)
}
}

View File

@@ -3,8 +3,10 @@ package db
import dev.inmo.micro_utils.repos.exposed.ExposedRepo
import dev.inmo.micro_utils.repos.exposed.initTable
import dev.inmo.tgbotapi.types.ChatId
import dev.inmo.tgbotapi.types.IdChatIdentifier
import model.ChatSettings
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.transactions.transaction
internal class WelcomeTable(
@@ -19,7 +21,7 @@ internal class WelcomeTable(
initTable()
}
fun get(chatId: ChatId): ChatSettings? = transaction(database) {
fun get(chatId: IdChatIdentifier): ChatSettings? = transaction(database) {
select { targetChatIdColumn.eq(chatId.chatId) }.limit(1).firstOrNull() ?.let {
ChatSettings(
ChatId(it[targetChatIdColumn]),
@@ -38,7 +40,7 @@ internal class WelcomeTable(
}.insertedCount > 0
}
fun unset(chatId: ChatId): Boolean = transaction(database) {
fun unset(chatId: IdChatIdentifier): Boolean = transaction(database) {
deleteWhere { targetChatIdColumn.eq(chatId.chatId) } > 0
}
}

View File

@@ -1,12 +1,13 @@
package model
import dev.inmo.tgbotapi.types.ChatId
import dev.inmo.tgbotapi.types.IdChatIdentifier
import dev.inmo.tgbotapi.types.MessageIdentifier
import kotlinx.serialization.Serializable
@Serializable
internal data class ChatSettings(
val targetChatId: ChatId,
val sourceChatId: ChatId,
val targetChatId: IdChatIdentifier,
val sourceChatId: IdChatIdentifier,
val sourceMessageId: MessageIdentifier
)