Skip to content

Commit 8dc07b9

Browse files
authored
Merge pull request #35 from /issues/31
Fix #31: Publish articles
2 parents 6551cb4 + c02aa53 commit 8dc07b9

File tree

15 files changed

+202
-5
lines changed

15 files changed

+202
-5
lines changed

herald/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ application {
1111
dependencies {
1212
implementation(libs.kotlinx.serialization.core)
1313
implementation(libs.kaml)
14+
implementation(libs.tgbotapi.extensions.api)
15+
implementation(project.projects.votes.dynamodb)
16+
implementation(project.projects.votes.tgbotapiExtensions)
17+
implementation(project.projects.votes.dynamodb)
1418

1519
testImplementation(libs.junit.jupiter.api)
1620
testImplementation(libs.junit.jupiter.params)

herald/processor/README.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
= Herald / Processor
2+
3+
link:../../votes/voting-processor/src/main/kotlin/by/jprof/telegram/bot/votes/voting_processor/VotingProcessor.kt[`VotingProcessor`] implementation for this scheduled messages poster.

herald/processor/build.gradle.kts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
plugins {
2+
kotlin("jvm")
3+
}
4+
5+
dependencies {
6+
api(project.projects.core)
7+
api(project.projects.votes)
8+
api(project.projects.votes.votingProcessor)
9+
implementation(libs.log4j.api)
10+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package by.jprof.telegram.bot.herald.processor
2+
3+
import by.jprof.telegram.bot.core.UpdateProcessor
4+
import by.jprof.telegram.bot.votes.dao.VotesDAO
5+
import by.jprof.telegram.bot.votes.voting_processor.VotingProcessor
6+
import dev.inmo.tgbotapi.bot.RequestsExecutor
7+
import dev.inmo.tgbotapi.types.update.CallbackQueryUpdate
8+
import dev.inmo.tgbotapi.types.update.abstracts.Update
9+
import org.apache.logging.log4j.LogManager
10+
11+
class HeraldVoteUpdateProcessor(
12+
votesDAO: VotesDAO,
13+
bot: RequestsExecutor,
14+
) : VotingProcessor(
15+
"HERALD",
16+
votesDAO,
17+
{ throw UnsupportedOperationException("Votes should be constructed elsewhere!") },
18+
bot,
19+
), UpdateProcessor {
20+
companion object {
21+
private val logger = LogManager.getLogger(HeraldVoteUpdateProcessor::class.java)!!
22+
}
23+
24+
override suspend fun process(update: Update) {
25+
when (update) {
26+
is CallbackQueryUpdate -> processCallbackQuery(update.data)
27+
}
28+
}
29+
}

herald/src/main/kotlin/by/jprof/telegram/bot/herald/App.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package by.jprof.telegram.bot.herald
22

33
import by.jprof.telegram.bot.herald.impl.post
44
import by.jprof.telegram.bot.herald.impl.postFile
5+
import by.jprof.telegram.bot.herald.impl.send
56

67
suspend fun main(args: Array<String>) {
78
val postFile = postFile() ?: run { println("No post for today"); return }
@@ -11,4 +12,8 @@ suspend fun main(args: Array<String>) {
1112
val post = post(postFile) ?: run { println("Cannot parse the file"); return }
1213

1314
println("Parsed the post: $post")
15+
16+
send(post)
17+
18+
println("Done")
1419
}
Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
package by.jprof.telegram.bot.herald.impl
22

3+
import by.jprof.telegram.bot.herald.model.Frontmatter
34
import by.jprof.telegram.bot.herald.model.Post
45
import com.charleskorn.kaml.Yaml
56
import kotlinx.serialization.decodeFromString
67
import java.nio.file.Path
8+
import kotlin.io.path.Path
9+
import kotlin.io.path.absolutePathString
10+
import kotlin.io.path.nameWithoutExtension
711
import kotlin.io.path.readText
12+
import kotlin.io.path.relativeTo
813
import kotlin.text.RegexOption.DOT_MATCHES_ALL
914
import kotlin.text.RegexOption.MULTILINE
1015

1116
fun post(path: Path): Post? {
17+
val cwd = Path("")
1218
val text = path.readText()
1319
val regex = Regex("-{3,}\\R(?<frontmatter>.*)\\R-{3,}\\s+(?<content>.*)", setOf(MULTILINE, DOT_MATCHES_ALL))
1420

@@ -17,7 +23,20 @@ fun post(path: Path): Post? {
1723

1824
val frontmatter = groups["frontmatter"]?.value ?: return null
1925
val content = groups["content"]?.value ?: return null
26+
val relativePath = path.relativeTo(cwd.toAbsolutePath())
2027

21-
Post(Yaml.default.decodeFromString(frontmatter), content)
28+
Post(
29+
relativePath.parent.toString() + "/" + relativePath.nameWithoutExtension,
30+
Yaml.default.decodeFromString<Frontmatter>(frontmatter).run {
31+
if (this.image == null) {
32+
this
33+
} else {
34+
this.copy(
35+
image = path.resolveSibling(this.image).absolutePathString()
36+
)
37+
}
38+
},
39+
content,
40+
)
2241
}
2342
}

herald/src/main/kotlin/by/jprof/telegram/bot/herald/impl/postFile.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ import java.nio.file.Path
44
import java.time.LocalDate
55
import java.time.format.DateTimeFormatter
66
import kotlin.io.path.Path
7+
import kotlin.io.path.absolute
78
import kotlin.io.path.exists
89

910
fun postFile(): Path? {
1011
val cwd = Path("")
1112
val today = LocalDate.now()
1213
val formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd")
1314

14-
return cwd.resolve(today.format(formatter) + ".md").takeIf { it.exists() }
15+
return cwd.resolve(today.format(formatter) + ".md").absolute().takeIf { it.exists() }
1516
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package by.jprof.telegram.bot.herald.impl
2+
3+
import by.jprof.telegram.bot.herald.model.Post
4+
import by.jprof.telegram.bot.votes.dynamodb.dao.VotesDAO
5+
import by.jprof.telegram.bot.votes.model.Votes
6+
import by.jprof.telegram.bot.votes.tgbotapi_extensions.toInlineKeyboardMarkup
7+
import dev.inmo.tgbotapi.bot.Ktor.telegramBot
8+
import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
9+
import dev.inmo.tgbotapi.extensions.api.send.media.sendPhoto
10+
import dev.inmo.tgbotapi.extensions.api.send.sendMessage
11+
import dev.inmo.tgbotapi.requests.abstracts.InputFile
12+
import dev.inmo.tgbotapi.requests.abstracts.MultipartFile
13+
import dev.inmo.tgbotapi.types.ParseMode.MarkdownV2ParseMode
14+
import dev.inmo.tgbotapi.types.chat.abstracts.UsernameChat
15+
import dev.inmo.tgbotapi.types.toChatId
16+
import dev.inmo.tgbotapi.utils.StorageFile
17+
import dev.inmo.tgbotapi.utils.extensions.escapeMarkdownV2Common
18+
import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider
19+
import software.amazon.awssdk.regions.Region
20+
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient
21+
import kotlin.io.path.Path
22+
import kotlin.io.path.absolute
23+
import kotlin.io.path.isRegularFile
24+
import kotlin.system.exitProcess
25+
26+
suspend fun send(post: Post) {
27+
val image = post.image()
28+
val votes = post.votes()
29+
30+
post.frontmatter.chats.forEach { chat ->
31+
when {
32+
image != null -> {
33+
println("Sending image to $chat")
34+
35+
bot.sendPhoto(
36+
chatId = chat.toChatId(),
37+
fileId = image,
38+
text = post.content.forChat(chat),
39+
parseMode = MarkdownV2ParseMode,
40+
replyMarkup = votes?.toInlineKeyboardMarkup(),
41+
)
42+
}
43+
else -> {
44+
println("Sending text to $chat")
45+
46+
bot.sendMessage(
47+
chatId = chat.toChatId(),
48+
text = post.content.forChat(chat),
49+
parseMode = MarkdownV2ParseMode,
50+
replyMarkup = votes?.toInlineKeyboardMarkup(),
51+
disableWebPagePreview = true,
52+
)
53+
}
54+
}
55+
}
56+
}
57+
58+
private val bot = telegramBot(System.getenv("TOKEN_TELEGRAM_BOT") ?: run {
59+
println("TOKEN_TELEGRAM_BOT is not set!")
60+
exitProcess(0)
61+
})
62+
63+
private val votesDAO = VotesDAO(
64+
DynamoDbAsyncClient
65+
.builder()
66+
.region(Region.US_EAST_1)
67+
.credentialsProvider(EnvironmentVariableCredentialsProvider.create())
68+
.build(),
69+
System.getenv("TABLE_VOTES") ?: run {
70+
println("TABLE_VOTES is not set!")
71+
exitProcess(0)
72+
}
73+
)
74+
75+
private fun Post.image(): InputFile? {
76+
val cwd = Path("").absolute()
77+
val imagePath = this.frontmatter.image?.let { cwd.resolve(it) }
78+
79+
return if (imagePath != null && imagePath.isRegularFile()) {
80+
MultipartFile(StorageFile(imagePath.toFile()))
81+
} else {
82+
null
83+
}
84+
}
85+
86+
private suspend fun Post.votes(): Votes? {
87+
return if (this.frontmatter.votes == null) {
88+
null
89+
} else {
90+
val votesId = "HERALD-${this.id}"
91+
92+
votesDAO.get(votesId) ?: Votes(votesId, this.frontmatter.votes)
93+
}
94+
}
95+
96+
private suspend fun String.forChat(chatId: Long): String {
97+
val chat = (bot.getChat(chatId.toChatId()) as? UsernameChat)?.username?.username ?: return this
98+
99+
return "${this.trimEnd()}\n\n${chat.escapeMarkdownV2Common()}"
100+
}

herald/src/main/kotlin/by/jprof/telegram/bot/herald/model/Frontmatter.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,5 @@ import kotlinx.serialization.Serializable
66
data class Frontmatter(
77
val chats: List<Long>,
88
val image: String? = null,
9-
val disableWebPagePreview: Boolean = false,
109
val votes: List<String>? = null,
1110
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package by.jprof.telegram.bot.herald.model
22

33
data class Post(
4+
val id: String,
45
val frontmatter: Frontmatter,
56
val content: String,
67
)

0 commit comments

Comments
 (0)