mirror of
https://github.com/Eyre-S/Coeur-Morny-Cono.git
synced 2024-11-25 20:47:38 +08:00
unset all function defaults config, fix universal command parse
unset the following defaults value: - master - trusted chat - dinner chat id - report to chat - medication notify to chat and make the related function can be shutdown by the new -1 defaults: - MedicationTimer daemon will not run when medication-notify-to-chat or notify-at-hour is not set - MornyReport will do not report when report-to is not set - OnCallMe will send ID_501 when there's no master - OnCallMe.requestLastDinner will send ID_501 when there's no dinner-chat fix when using universal command parse may throw exception
This commit is contained in:
parent
985fde9aa2
commit
45a85e15f5
@ -5,7 +5,7 @@ MORNY_ARCHIVE_NAME = morny-coeur
|
||||
MORNY_CODE_STORE = https://github.com/Eyre-S/Coeur-Morny-Cono
|
||||
MORNY_COMMIT_PATH = https://github.com/Eyre-S/Coeur-Morny-Cono/commit/%s
|
||||
|
||||
VERSION = 1.0.0-RC5
|
||||
VERSION = 1.0.0-RC6
|
||||
|
||||
USE_DELTA = false
|
||||
VERSION_DELTA =
|
||||
|
@ -167,16 +167,16 @@ public class MornyConfig {
|
||||
@Nullable public String telegramBotApiServer4File = null;
|
||||
@Nullable public String telegramBotKey = null;
|
||||
@Nullable public String telegramBotUsername = null;
|
||||
public long trustedMaster = 793274677L;
|
||||
public long trustedChat = -1001541451710L;
|
||||
public long trustedMaster = -1L;
|
||||
public long trustedChat = -1L;
|
||||
public boolean eventIgnoreOutdated = false;
|
||||
public long eventOutdatedTimestamp = -1;
|
||||
public boolean commandLoginRefresh = false;
|
||||
public boolean commandLogoutClear = false;
|
||||
@Nonnull public final Set<Long> dinnerTrustedReaders = new HashSet<>();
|
||||
public long dinnerChatId = -1001707106392L;
|
||||
public long reportToChat = -1001650050443L;
|
||||
public long medicationNotifyToChat = -1001729016815L;
|
||||
public long dinnerChatId = -1L;
|
||||
public long reportToChat = -1L;
|
||||
public long medicationNotifyToChat = -1L;
|
||||
@Nonnull public ZoneOffset medicationTimerUseTimezone = ZoneOffset.UTC;
|
||||
@Nonnull public final Set<Integer> medicationNotifyAt = new HashSet<>();
|
||||
|
||||
|
@ -2,11 +2,15 @@ package cc.sukazyo.cono.morny
|
||||
|
||||
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.{LimboChat, LimboUser}
|
||||
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Chat.*
|
||||
import cc.sukazyo.cono.morny.Log.logger
|
||||
import com.pengrad.telegrambot.model.ChatMember.Status
|
||||
import com.pengrad.telegrambot.TelegramBot
|
||||
|
||||
class MornyTrusted (using coeur: MornyCoeur)(using config: MornyConfig) {
|
||||
|
||||
if config.trustedMaster == -1 then
|
||||
logger warn "You have not set your Morny's master.\n it may have some issues on controlling your bot."
|
||||
|
||||
def isTrusted (userId: Long): Boolean =
|
||||
given TelegramBot = coeur.account
|
||||
if userId == config.trustedMaster then true
|
||||
|
@ -21,6 +21,7 @@ class OnCallMe (using coeur: MornyCoeur) extends EventListener {
|
||||
if update.message.chat.`type` != (Chat.Type Private) then return false
|
||||
|
||||
//noinspection ScalaUnnecessaryParentheses
|
||||
val success = if me == -1 then false else
|
||||
(update.message.text toLowerCase) match
|
||||
case "steam" | "sbeam" | "sdeam" =>
|
||||
requestItem(update.message.from, "<b>STEAM LIBRARY</b>")
|
||||
@ -33,23 +34,32 @@ class OnCallMe (using coeur: MornyCoeur) extends EventListener {
|
||||
case _ =>
|
||||
return false
|
||||
|
||||
if success then
|
||||
coeur.account exec SendSticker(
|
||||
update.message.chat.id,
|
||||
TelegramStickers ID_SENT
|
||||
).replyToMessageId(update.message.messageId)
|
||||
else
|
||||
coeur.account exec SendSticker(
|
||||
update.message.chat.id,
|
||||
TelegramStickers ID_501
|
||||
).replyToMessageId(update.message.messageId)
|
||||
|
||||
true
|
||||
|
||||
}
|
||||
|
||||
private def requestItem (user: User, itemHTML: String, extra: String|Null = null): Unit =
|
||||
private def requestItem (user: User, itemHTML: String, extra: String|Null = null): Boolean =
|
||||
coeur.account exec SendMessage(
|
||||
me,
|
||||
s"""request $itemHTML
|
||||
|from ${user.fullnameRefHTML}${if extra == null then "" else "\n"+extra}"""
|
||||
.stripMargin
|
||||
).parseMode(ParseMode HTML)
|
||||
true
|
||||
|
||||
private def requestLastDinner (req: Message): Unit = {
|
||||
private def requestLastDinner (req: Message): Boolean = {
|
||||
if coeur.config.dinnerChatId == -1 then return false
|
||||
var isAllowed = false
|
||||
var lastDinnerData: Message|Null = null
|
||||
if (coeur.trusted isTrusted_dinnerReader req.from.id) {
|
||||
@ -86,8 +96,9 @@ class OnCallMe (using coeur: MornyCoeur) extends EventListener {
|
||||
)
|
||||
}
|
||||
|
||||
private def requestCustom (message: Message): Unit =
|
||||
private def requestCustom (message: Message): Boolean =
|
||||
requestItem(message.from, "<u>[???]</u>")
|
||||
coeur.account exec ForwardMessage(me, message.chat.id, message.messageId)
|
||||
true
|
||||
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ class OnUserSlashAction (using coeur: MornyCoeur) extends EventListener {
|
||||
// scala, those commented code is removed permanently.
|
||||
// these message, here to remember the old DP7.
|
||||
|
||||
val actions = UniversalCommand(text)
|
||||
val actions = UniversalCommand.Lossy(text)
|
||||
actions(0) = actions(0) substring 1
|
||||
|
||||
actions(0)
|
||||
|
@ -27,6 +27,12 @@ class MedicationTimer (using coeur: MornyCoeur) extends Thread {
|
||||
private var lastNotify_messageId: Option[Int] = None
|
||||
|
||||
override def run (): Unit = {
|
||||
|
||||
if ((notify_toChat == -1) || (notify_atHour isEmpty)) {
|
||||
logger info "Medication Timer disabled : related param is not complete set"
|
||||
return
|
||||
}
|
||||
|
||||
logger info "Medication Timer started."
|
||||
while (!this.isInterrupted) {
|
||||
try {
|
||||
@ -47,6 +53,7 @@ class MedicationTimer (using coeur: MornyCoeur) extends Thread {
|
||||
coeur.daemons.reporter.exception(e)
|
||||
}
|
||||
logger info "Medication Timer stopped."
|
||||
|
||||
}
|
||||
|
||||
private def sendNotification(): Unit = {
|
||||
|
@ -15,7 +15,12 @@ import com.pengrad.telegrambot.response.BaseResponse
|
||||
|
||||
class MornyReport (using coeur: MornyCoeur) {
|
||||
|
||||
private val enabled = coeur.config.reportToChat != -1
|
||||
if !enabled then
|
||||
logger info "Morny Report is disabled : report chat is set to -1"
|
||||
|
||||
private def executeReport[T <: BaseRequest[T, R], R<: BaseResponse] (report: T): Unit = {
|
||||
if !enabled then return;
|
||||
try {
|
||||
coeur.account exec report
|
||||
} catch case e: EventRuntimeException.ActionFailed => {
|
||||
@ -70,8 +75,7 @@ class MornyReport (using coeur: MornyCoeur) {
|
||||
).parseMode(ParseMode HTML))
|
||||
}
|
||||
|
||||
//noinspection ScalaWeakerAccess
|
||||
def sectionConfigFields (config: MornyConfig): String = {
|
||||
private def sectionConfigFields (config: MornyConfig): String = {
|
||||
val echo = StringBuilder()
|
||||
for (field <- config.getClass.getFields) {
|
||||
// language=html
|
||||
@ -100,17 +104,18 @@ class MornyReport (using coeur: MornyCoeur) {
|
||||
}
|
||||
|
||||
def reportCoeurExit (): Unit = {
|
||||
val causedTag = coeur.exitReason match
|
||||
def _causedTag = coeur.exitReason match
|
||||
case Some(_exitReason) => _exitReason match
|
||||
case u: User => u.fullnameRefHTML
|
||||
case a => /*language=html*/ s"<code>${h(a.toString)}</code>"
|
||||
case None => "UNKNOWN reason"
|
||||
case u: Some[User] => u.get.fullnameRefHTML
|
||||
case a: Some[_] => /*language=html*/ s"<code>${h(a.get.toString)}</code>"
|
||||
executeReport(SendMessage(
|
||||
coeur.config.reportToChat,
|
||||
// language=html
|
||||
s"""<b>▌Morny Exited</b>
|
||||
|from user @${coeur.username}
|
||||
|
|
||||
|by: $causedTag"""
|
||||
|by: $_causedTag"""
|
||||
.stripMargin
|
||||
).parseMode(ParseMode HTML))
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ public class TelegramStickers {
|
||||
public static final String ID_SAVED = "CAACAgEAAx0CSQh32gABBExuYdB_G0srfhQldRWkBYxWzCOv4-IAApooAAJ4_MYFcjuNZszfQcQjBA";
|
||||
public static final String ID_PROGYNOVA = "CAACAgUAAxkBAAICm2KEuL7UQqNP7vSPCg2DHJIND6UsAAKLAwACH4WSBszIo722aQ3jJAQ";
|
||||
public static final String ID_NETWORK_ERR = "CAACAgEAAxkBAAID0WNJgNEkD726KW4vZeFlw0FlVVyNAAIXJgACePzGBb50o7O1RbxoKgQ";
|
||||
public static final String ID_501 = "CAACAgEAAxkBAAIHbGUhJ8zm2Sb_c0YU-DYQ6xb-ZDtaAAKdJwACePzGBTOftDZL6X7vMAQ";
|
||||
|
||||
@Nonnull
|
||||
public static Map<String, String> map () {
|
||||
|
@ -9,7 +9,13 @@ import scala.util.boundary
|
||||
*/
|
||||
object UniversalCommand {
|
||||
|
||||
def apply (input: String): Array[String] = {
|
||||
opaque type StrictMode = Boolean
|
||||
//noinspection ScalaWeakerAccess
|
||||
val strict: StrictMode = true
|
||||
//noinspection ScalaWeakerAccess
|
||||
val lossy: StrictMode = false
|
||||
|
||||
def apply (using strict: StrictMode = strict)(input: String): Array[String] = {
|
||||
|
||||
val builder = ArrayBuffer.empty[String]
|
||||
|
||||
@ -38,26 +44,29 @@ object UniversalCommand {
|
||||
val _inside_tag = input(i)
|
||||
boundary { while (true) {
|
||||
i=i+1
|
||||
if (i >= input.length) throw IllegalArgumentException("UniversalCommand: unclosed quoted text")
|
||||
if (i >= input.length)
|
||||
if strict then throw IllegalArgumentException("UniversalCommand: unclosed quoted text")
|
||||
else boundary.break()
|
||||
if (input(i) == _inside_tag)
|
||||
boundary.break()
|
||||
else if (input(i) isUnsupported)
|
||||
else if (input(i) isUnsupported) && strict then
|
||||
throw IllegalArgumentException("UniversalCommand: unsupported new-line")
|
||||
else if (input(i) isQuote)
|
||||
else if (input(i) isQuote) && strict then
|
||||
throw IllegalArgumentException("UniversalCommand: mixed \" and ' used")
|
||||
else if (input(i) isEscapeChar)
|
||||
if (i+1 >= input.length) throw IllegalArgumentException("UniversalCommand: \\ in the end")
|
||||
if (input(i+1) escapableInQuote)
|
||||
if (i+1 >= input.length) && strict then
|
||||
throw IllegalArgumentException("UniversalCommand: \\ in the end")
|
||||
if ((i+1 < input.length) && (input(i+1) escapableInQuote))
|
||||
i=i+1
|
||||
arg += input(i)
|
||||
else
|
||||
arg += input(i)
|
||||
}}
|
||||
} else if (input(i) isUnsupported) {
|
||||
} else if ((input(i) isUnsupported) && strict) {
|
||||
throw IllegalArgumentException("UniversalCommand: unsupported new-line")
|
||||
} else if (input(i) isEscapeChar) {
|
||||
if (i + 1 >= input.length) throw IllegalArgumentException("UniversalCommand: \\ in the end")
|
||||
if (input(i+1) escapable)
|
||||
if (i + 1 >= input.length) && strict then throw IllegalArgumentException("UniversalCommand: \\ in the end")
|
||||
if ((i+1 < input.length) && (input(i+1) escapable))
|
||||
i=i+1
|
||||
arg += input(i)
|
||||
} else {
|
||||
@ -71,4 +80,7 @@ object UniversalCommand {
|
||||
|
||||
}
|
||||
|
||||
object Lossy:
|
||||
def apply (input: String): Array[String] = UniversalCommand(using lossy)(input)
|
||||
|
||||
}
|
||||
|
@ -25,7 +25,8 @@ object InputCommand {
|
||||
)
|
||||
}
|
||||
|
||||
//noinspection NoTailRecursionAnnotation
|
||||
def apply (input: String): InputCommand =
|
||||
InputCommand(UniversalCommand(input))
|
||||
InputCommand(UniversalCommand.Lossy(input))
|
||||
|
||||
}
|
||||
|
@ -9,50 +9,93 @@ class UniversalCommandTest extends MornyTests with Matchers with TableDrivenProp
|
||||
"while formatting command from String :" - {
|
||||
|
||||
import cc.sukazyo.cono.morny.util.UniversalCommand as Cmd
|
||||
import cc.sukazyo.cono.morny.util.UniversalCommand.Lossy as Lmd
|
||||
def whileLossy (info: String): String = "in lossy mode " + info
|
||||
def whileStrict (info: String): String = "in strict mode" + info
|
||||
|
||||
raw"args should be separated by (\u0020) ascii-space" in:
|
||||
Cmd("a b c delta e") shouldEqual Array("a", "b", "c", "delta", "e");
|
||||
Cmd("a b c delta e") shouldEqual Array("a", "b", "c", "delta", "e")
|
||||
Lmd("a b c delta e") shouldEqual Array("a", "b", "c", "delta", "e")
|
||||
"args should not be separated by non-ascii spaces" in:
|
||||
Cmd("tests ダタ セト") shouldEqual Array("tests", "ダタ セト");
|
||||
Cmd("tests ダタ セト") shouldEqual Array("tests", "ダタ セト")
|
||||
Lmd("tests ダタ セト") shouldEqual Array("tests", "ダタ セト")
|
||||
"multiple ascii-spaces should not generate empty arg in middle" in:
|
||||
Cmd("tests some of data") shouldEqual Array("tests", "some", "of", "data");
|
||||
Cmd("tests some of data") shouldEqual Array("tests", "some", "of", "data")
|
||||
Lmd("tests some of data") shouldEqual Array("tests", "some", "of", "data")
|
||||
|
||||
"""texts and ascii-spaces in '' should grouped in one arg""" in:
|
||||
Cmd("""tests 'data set'""") shouldEqual Array("tests", "data set");
|
||||
Cmd("""tests 'data set'""") shouldEqual Array("tests", "data set")
|
||||
Lmd("""tests 'data set'""") shouldEqual Array("tests", "data set")
|
||||
"""texts and ascii-spaces in "" should grouped in one arg""" in :
|
||||
Cmd("""tests "data set"""") shouldEqual Array("tests", "data set");
|
||||
"""mixed ' and " should throws IllegalArgumentsException""" in:
|
||||
an [IllegalArgumentException] should be thrownBy Cmd("""tests "data set' "of it'""");
|
||||
"with ' not closed should throws IllegalArgumentException" in:
|
||||
an [IllegalArgumentException] should be thrownBy Cmd("""use 'it """);
|
||||
Cmd("""tests "data set"""") shouldEqual Array("tests", "data set")
|
||||
Lmd("""tests "data set"""") shouldEqual Array("tests", "data set")
|
||||
"""texts nested '' should grouped in one arg""" in :
|
||||
Cmd("""tests some:'data set'.message is""") shouldEqual Array("tests", "some:data set.message", "is")
|
||||
Lmd("""tests some:'data set'.message is""") shouldEqual Array("tests", "some:data set.message", "is")
|
||||
"""texts and "" nested '' should grouped in one arg""" in :
|
||||
Cmd("""tests "arg1 x":'arg2 y' param""") shouldEqual Array("tests", "arg1 x:arg2 y", "param")
|
||||
Lmd("""tests "arg1 x":"arg2 y" param""") shouldEqual Array("tests", "arg1 x:arg2 y", "param")
|
||||
"with ' not closed" - {
|
||||
whileStrict("should throws IllegalArgumentException") in:
|
||||
an[IllegalArgumentException] should be thrownBy Cmd("""use 'it """)
|
||||
whileLossy("should be cut at end") in:
|
||||
Lmd("use 'it ") shouldEqual Array("use", "it ")
|
||||
}
|
||||
"""mixed ' and """" - {
|
||||
whileStrict("should throws IllegalArgumentsException") in:
|
||||
an[IllegalArgumentException] should be thrownBy Cmd("""tests "data set' "of it'""")
|
||||
whileLossy("should be seen as a normal character") in:
|
||||
Lmd("""tests "data set' "of it'""") shouldEqual Array("tests", "data set' of", "it")
|
||||
}
|
||||
|
||||
raw"\ should escape itself" in:
|
||||
Cmd(raw"input \\data") shouldEqual Array("input", "\\data");
|
||||
Cmd(raw"input \\data") shouldEqual Array("input", "\\data")
|
||||
Lmd(raw"input \\data") shouldEqual Array("input", "\\data")
|
||||
raw"\ should escape ascii-space, makes it processed as a normal character" in:
|
||||
Cmd(raw"input data\ set") shouldEqual Array("input", "data set");
|
||||
Cmd(raw"input data\ set") shouldEqual Array("input", "data set")
|
||||
Lmd(raw"input data\ set") shouldEqual Array("input", "data set")
|
||||
raw"\ should escape ascii-space, makes it can be an arg body" in:
|
||||
Cmd(raw"input \ some-thing") shouldEqual Array("input", " ", "some-thing");
|
||||
Cmd(raw"input \ some-thing") shouldEqual Array("input", " ", "some-thing")
|
||||
Lmd(raw"input \ some-thing") shouldEqual Array("input", " ", "some-thing")
|
||||
raw"""\ should escape "", makes it processed as a normal character""" in :
|
||||
Cmd(raw"""use \"inputted""") shouldEqual Array("use", "\"inputted");
|
||||
Cmd(raw"""use \"inputted""") shouldEqual Array("use", "\"inputted")
|
||||
Lmd(raw"""use \"inputted""") shouldEqual Array("use", "\"inputted")
|
||||
raw"\ should escape '', makes it processed as a normal character" in:
|
||||
Cmd(raw"use \'inputted") shouldEqual Array("use", "'inputted");
|
||||
Cmd(raw"use \'inputted") shouldEqual Array("use", "'inputted")
|
||||
Lmd(raw"use \'inputted") shouldEqual Array("use", "'inputted")
|
||||
raw"\ should escape itself which inside a quoted scope" in:
|
||||
Cmd(raw"use 'quoted \\ body'") shouldEqual Array("use", "quoted \\ body");
|
||||
Cmd(raw"use 'quoted \\ body'") shouldEqual Array("use", "quoted \\ body")
|
||||
Lmd(raw"use 'quoted \\ body'") shouldEqual Array("use", "quoted \\ body")
|
||||
raw"""\ should escape " which inside a "" scope""" in:
|
||||
Cmd(raw"""in "quoted \" body" body""") shouldEqual Array("in", "quoted \" body", "body");
|
||||
Cmd(raw"""in "quoted \" body" body""") shouldEqual Array("in", "quoted \" body", "body")
|
||||
Lmd(raw"""in "quoted \" body" body""") shouldEqual Array("in", "quoted \" body", "body")
|
||||
raw"""\ should escape ' which inside a "" scope""" in :
|
||||
Cmd(raw"""in "not-quoted \' body" body""") shouldEqual Array("in", "not-quoted ' body", "body");
|
||||
Cmd(raw"""in "not-quoted \' body" body""") shouldEqual Array("in", "not-quoted ' body", "body")
|
||||
Lmd(raw"""in "not-quoted \' body" body""") shouldEqual Array("in", "not-quoted ' body", "body")
|
||||
raw"""\ should escape ' which inside a '' scope""" in :
|
||||
Cmd(raw"""in 'quoted \' body' body""") shouldEqual Array("in", "quoted ' body", "body");
|
||||
Cmd(raw"""in 'quoted \' body' body""") shouldEqual Array("in", "quoted ' body", "body")
|
||||
Lmd(raw"""in 'quoted \' body' body""") shouldEqual Array("in", "quoted ' body", "body")
|
||||
raw"""\ should escape " which inside a ' scope""" in :
|
||||
Cmd(raw"""in 'not-quoted \" body' body""") shouldEqual Array("in", "not-quoted \" body", "body");
|
||||
Cmd(raw"""in 'not-quoted \" body' body""") shouldEqual Array("in", "not-quoted \" body", "body")
|
||||
Lmd(raw"""in 'not-quoted \" body' body""") shouldEqual Array("in", "not-quoted \" body", "body")
|
||||
raw"\ should not escape ascii-space which inside a quoted scope" in:
|
||||
Cmd(raw"""'quoted \ do not escape' did""") shouldEqual Array(raw"quoted \ do not escape", "did");
|
||||
raw"with \ in the end should throws IllegalArgumentException" in:
|
||||
an [IllegalArgumentException] should be thrownBy Cmd("something error!\\");
|
||||
Cmd(raw"""'quoted \ do not escape' did""") shouldEqual Array(raw"quoted \ do not escape", "did")
|
||||
Lmd(raw"""'quoted \ do not escape' did""") shouldEqual Array(raw"quoted \ do not escape", "did")
|
||||
raw"with \ in the end" - {
|
||||
whileStrict("should throws IllegalArgumentException") in:
|
||||
an [IllegalArgumentException] should be thrownBy Cmd("something error!\\")
|
||||
whileLossy("should seen as normal char") in:
|
||||
Lmd("something error!\\") shouldEqual Array("something", "error!\\")
|
||||
}
|
||||
|
||||
|
||||
"with multi-line input" - {
|
||||
whileStrict("should throws IllegalArgumentException") in:
|
||||
an [IllegalArgumentException] should be thrownBy Cmd("something will\nhave a new line")
|
||||
whileLossy("should keep new-line char origin like") in:
|
||||
Lmd("something will\nhave a new line") shouldEqual Array("something", "will\nhave", "a", "new", "line")
|
||||
}
|
||||
|
||||
"with multi-line input should throws IllegalArgumentException" in:
|
||||
an [IllegalArgumentException] should be thrownBy Cmd("something will\nhave a new line");
|
||||
|
||||
val example_special_character = Table(
|
||||
"char",
|
||||
@ -68,6 +111,8 @@ class UniversalCommandTest extends MornyTests with Matchers with TableDrivenProp
|
||||
s"input with special character ($char) should keep origin like" in {
|
||||
Cmd(s"$char dataset data[$char]contains parsed") shouldEqual
|
||||
Array(char, "dataset", s"data[$char]contains", "parsed")
|
||||
Lmd(s"$char dataset data[$char]contains parsed") shouldEqual
|
||||
Array(char, "dataset", s"data[$char]contains", "parsed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user