Skip to content

Commit 733b3ae

Browse files
committed
Time info for messages and mentions
1 parent 134f8b9 commit 733b3ae

File tree

5 files changed

+172
-0
lines changed

5 files changed

+172
-0
lines changed

runners/lambda/src/main/kotlin/by/jprof/telegram/bot/runners/lambda/config/pipeline.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import by.jprof.telegram.bot.quizoji.QuizojiOptionUpdateProcessor
1717
import by.jprof.telegram.bot.quizoji.QuizojiQuestionUpdateProcessor
1818
import by.jprof.telegram.bot.quizoji.QuizojiStartCommandUpdateProcessor
1919
import by.jprof.telegram.bot.quizoji.QuizojiVoteUpdateProcessor
20+
import by.jprof.telegram.bot.times.TimeCommandUpdateProcessor
2021
import by.jprof.telegram.bot.times.TimeZoneCommandUpdateProcessor
2122
import by.jprof.telegram.bot.youtube.YouTubeUpdateProcessor
2223
import dev.inmo.tgbotapi.utils.PreviewFeature
@@ -145,4 +146,11 @@ val pipelineModule = module {
145146
bot = get(),
146147
)
147148
}
149+
150+
single<UpdateProcessor>(named("TimeCommandUpdateProcessor")) {
151+
TimeCommandUpdateProcessor(
152+
timeZoneDAO = get(),
153+
bot = get(),
154+
)
155+
}
148156
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package by.jprof.telegram.bot.times
2+
3+
import by.jprof.telegram.bot.core.UpdateProcessor
4+
import by.jprof.telegram.bot.times.timezones.dao.TimeZoneDAO
5+
import by.jprof.telegram.bot.times.timezones.model.TimeZone
6+
import by.jprof.telegram.bot.times.utils.mentionDateTime
7+
import by.jprof.telegram.bot.times.utils.messageDateTime
8+
import dev.inmo.tgbotapi.CommonAbstracts.FromUser
9+
import dev.inmo.tgbotapi.bot.RequestsExecutor
10+
import dev.inmo.tgbotapi.extensions.api.send.reply
11+
import dev.inmo.tgbotapi.extensions.utils.asBaseMessageUpdate
12+
import dev.inmo.tgbotapi.extensions.utils.asBotCommandTextSource
13+
import dev.inmo.tgbotapi.extensions.utils.asContentMessage
14+
import dev.inmo.tgbotapi.extensions.utils.asMentionTextSource
15+
import dev.inmo.tgbotapi.extensions.utils.asTextContent
16+
import dev.inmo.tgbotapi.extensions.utils.asTextMentionTextSource
17+
import dev.inmo.tgbotapi.types.ParseMode.MarkdownV2ParseMode
18+
import dev.inmo.tgbotapi.types.message.abstracts.Message
19+
import dev.inmo.tgbotapi.types.message.abstracts.PossiblyReplyMessage
20+
import dev.inmo.tgbotapi.types.message.content.TextContent
21+
import dev.inmo.tgbotapi.types.update.abstracts.Update
22+
import java.time.Instant
23+
import java.time.LocalDateTime
24+
import java.time.ZoneId
25+
import java.time.ZoneOffset
26+
import org.apache.logging.log4j.LogManager
27+
28+
class TimeCommandUpdateProcessor(
29+
private val timeZoneDAO: TimeZoneDAO,
30+
private val bot: RequestsExecutor,
31+
) : UpdateProcessor {
32+
companion object {
33+
private val logger = LogManager.getLogger(TimeCommandUpdateProcessor::class.java)!!
34+
}
35+
36+
override suspend fun process(update: Update) {
37+
val update = update.asBaseMessageUpdate() ?: return
38+
val message = update.data.asContentMessage() ?: return
39+
val text = message.content.asTextContent() ?: return
40+
41+
if (text.textSources.mapNotNull { it.asBotCommandTextSource() }.none { it.command == "time" }) {
42+
return
43+
}
44+
45+
val reply = """
46+
${replyText(message)}
47+
48+
${mentionsText(text, message)}
49+
""".trimIndent().trim()
50+
51+
bot.reply(to = message, text = reply, parseMode = MarkdownV2ParseMode)
52+
}
53+
54+
private suspend fun replyText(message: Message): String {
55+
val message = (message as? PossiblyReplyMessage)?.replyTo ?: return ""
56+
val author = (message as? FromUser)?.user ?: return ""
57+
val timeZone = timeZoneDAO.get(author.id.chatId, message.chat.id.chatId) ?: return ""
58+
val messageTime = Instant.ofEpochMilli(message.date.unixMillisLong).toLocalDateTime(timeZone) ?: return ""
59+
val now = Instant.now().toLocalDateTime(timeZone) ?: return ""
60+
61+
logger.info(
62+
"Replying to {}. Author: {}. TimeZone: {}. Message time: {}, current time: {}", message, author, timeZone, messageTime, now
63+
)
64+
65+
return messageDateTime(messageTime, now)
66+
}
67+
68+
private suspend fun mentionsText(text: TextContent, message: Message): String {
69+
val mentions = text.textSources.mapNotNull { it.asMentionTextSource() }
70+
val textMentions = text.textSources.mapNotNull { it.asTextMentionTextSource() }
71+
val mentionsWithTimeZones = mentions.mapNotNull {
72+
val timeZone = timeZoneDAO.getByUsername(it.source, message.chat.id.chatId)
73+
74+
if (timeZone == null) {
75+
null
76+
} else {
77+
it.source to timeZone
78+
}
79+
}
80+
val textMentionsWithTimeZones = textMentions.mapNotNull {
81+
val timeZone = timeZoneDAO.get(it.user.id.chatId, message.chat.id.chatId)
82+
83+
if (timeZone == null) {
84+
null
85+
} else {
86+
it.source to timeZone
87+
}
88+
}
89+
val allMentions = mentionsWithTimeZones + textMentionsWithTimeZones
90+
val now = Instant.now()
91+
92+
logger.info(
93+
"Mentions: {}. Text mentions: {}. Combined mentions with TimeZones: {}", mentions, textMentions, allMentions
94+
)
95+
96+
return allMentions.mapNotNull { (who, timeZone) ->
97+
val userTime = now.toLocalDateTime(timeZone)
98+
99+
mentionDateTime(who, userTime ?: return@mapNotNull null)
100+
}.joinToString("\n")
101+
}
102+
103+
private fun Instant.toLocalDateTime(timeZone: TimeZone): LocalDateTime? =
104+
if (timeZone.zoneId != null) {
105+
this.atZone(ZoneId.of(timeZone.zoneId)).toLocalDateTime()
106+
} else if (timeZone.offset != null) {
107+
this.atOffset(ZoneOffset.ofTotalSeconds(timeZone.offset!!)).toLocalDateTime()
108+
} else {
109+
null
110+
}
111+
}

times/src/main/kotlin/by/jprof/telegram/bot/times/TimeZoneCommandUpdateProcessor.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class TimeZoneCommandUpdateProcessor(
4949
private suspend fun setTimeZone(timeZoneRequest: TimeZoneRequest) {
5050
val timeZone = TimeZone(
5151
user = timeZoneRequest.user.id.chatId,
52+
username = timeZoneRequest.user.username?.username,
5253
chat = timeZoneRequest.chat.id.chatId,
5354
).run {
5455
when (timeZoneRequest.value) {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package by.jprof.telegram.bot.times.utils
2+
3+
import java.text.FieldPosition
4+
import java.text.Format
5+
import java.text.ParsePosition
6+
import java.time.LocalDateTime
7+
8+
class LocalDateTimeFormat : Format() {
9+
override fun format(obj: Any, toAppendTo: StringBuffer, pos: FieldPosition): StringBuffer {
10+
val date = (obj as? LocalDateTime) ?: throw IllegalArgumentException()
11+
12+
toAppendTo.append("%1$02d".format(date.dayOfMonth))
13+
toAppendTo.append(".")
14+
toAppendTo.append("%1$02d".format(date.monthValue))
15+
toAppendTo.append(".")
16+
toAppendTo.append("%1$04d".format(date.year))
17+
toAppendTo.append(" ")
18+
toAppendTo.append("%1$02d".format(date.hour))
19+
toAppendTo.append(":")
20+
toAppendTo.append("%1$02d".format(date.minute))
21+
22+
return toAppendTo
23+
}
24+
25+
override fun parseObject(source: String?, pos: ParsePosition): Any? = null
26+
}

times/src/main/kotlin/by/jprof/telegram/bot/times/utils/messages.kt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package by.jprof.telegram.bot.times.utils
33
import by.jprof.telegram.bot.times.timezones.model.TimeZone
44
import dev.inmo.tgbotapi.utils.extensions.escapeMarkdownV2Common
55
import java.text.MessageFormat
6+
import java.time.LocalDateTime
67

78
private val unrecognizedValueMessages = listOf(
89
"Не могу разобрать таймзону\\!",
@@ -45,3 +46,28 @@ internal fun timeZoneSet(timeZone: TimeZone?): String {
4546
)
4647
}
4748
}
49+
50+
private val messageDateTimeMessages = listOf(
51+
"Время у автора на момент написания сообщения: {0}. А сейчас у автора: {1}."
52+
)
53+
54+
internal fun messageDateTime(messageDate: LocalDateTime, now: LocalDateTime): String {
55+
return MessageFormat(messageDateTimeMessages.random()).apply {
56+
setFormat(0, LocalDateTimeFormat())
57+
setFormat(1, LocalDateTimeFormat())
58+
}.format(
59+
arrayOf(messageDate, now)
60+
).escapeMarkdownV2Common()
61+
}
62+
63+
private val mentionDateTimeMessages = listOf(
64+
"Время у {0}: {1}."
65+
)
66+
67+
internal fun mentionDateTime(who: String, date: LocalDateTime): String {
68+
return MessageFormat(mentionDateTimeMessages.random()).apply {
69+
setFormat(1, LocalDateTimeFormat())
70+
}.format(
71+
arrayOf(who, date)
72+
).escapeMarkdownV2Common()
73+
}

0 commit comments

Comments
 (0)