mirror of
https://github.com/dyrkin/luxmed-bot.git
synced 2025-12-21 21:33:12 +01:00
Simplified conversation logic
This commit is contained in:
@@ -38,12 +38,12 @@ class Account(val userId: UserId, bot: Bot, dataService: DataService, val locali
|
|||||||
entryPoint(askAction)
|
entryPoint(askAction)
|
||||||
|
|
||||||
def askAction: Step =
|
def askAction: Step =
|
||||||
question { _ =>
|
ask { _ =>
|
||||||
val credentials = dataService.getUserCredentials(userId.userId)
|
val credentials = dataService.getUserCredentials(userId.userId)
|
||||||
val currentAccount = credentials.find(c => c.accountId == userId.accountId).getOrElse(sys.error("Can't determine current account"))
|
val currentAccount = credentials.find(c => c.accountId == userId.accountId).getOrElse(sys.error("Can't determine current account"))
|
||||||
val buttons = Seq(Button(lang.addAccount, -1L), Button(lang.deleteAccount, -2L)) ++ credentials.map(c => Button(s"🔐️ ${c.username}", c.accountId))
|
val buttons = Seq(Button(lang.addAccount, -1L), Button(lang.deleteAccount, -2L)) ++ credentials.map(c => Button(s"🔐️ ${c.username}", c.accountId))
|
||||||
bot.sendMessage(userId.source, lang.pleaseChooseAccount(currentAccount.username), inlineKeyboard = createInlineKeyboard(buttons, columns = 1))
|
bot.sendMessage(userId.source, lang.pleaseChooseAccount(currentAccount.username), inlineKeyboard = createInlineKeyboard(buttons, columns = 1))
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(cmd@CallbackCommand(actionStr), _) =>
|
case Msg(cmd@CallbackCommand(actionStr), _) =>
|
||||||
val action = actionStr.toLong
|
val action = actionStr.toLong
|
||||||
action match {
|
action match {
|
||||||
|
|||||||
@@ -84,12 +84,12 @@ class Book(val userId: UserId, bot: Bot, apiService: ApiService, dataService: Da
|
|||||||
}(requestNext = requestDateFrom)
|
}(requestNext = requestDateFrom)
|
||||||
|
|
||||||
private def requestDateFrom: Step =
|
private def requestDateFrom: Step =
|
||||||
question { bookingData =>
|
ask { bookingData =>
|
||||||
datePicker ! InitConversation
|
datePicker ! InitConversation
|
||||||
datePicker ! StartConversation
|
datePicker ! StartConversation
|
||||||
datePicker ! DateFromMode
|
datePicker ! DateFromMode
|
||||||
datePicker ! bookingData.dateFrom
|
datePicker ! bookingData.dateFrom
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(cmd: Command, _) =>
|
case Msg(cmd: Command, _) =>
|
||||||
datePicker ! cmd
|
datePicker ! cmd
|
||||||
stay()
|
stay()
|
||||||
@@ -98,37 +98,28 @@ class Book(val userId: UserId, bot: Bot, apiService: ApiService, dataService: Da
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def requestDateTo: Step =
|
private def requestDateTo: Step =
|
||||||
question { bookingData =>
|
ask { bookingData =>
|
||||||
datePicker ! InitConversation
|
datePicker ! InitConversation
|
||||||
datePicker ! StartConversation
|
datePicker ! StartConversation
|
||||||
datePicker ! DateToMode
|
datePicker ! DateToMode
|
||||||
datePicker ! bookingData.dateFrom.plusDays(1)
|
datePicker ! bookingData.dateFrom.plusDays(1)
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(cmd: Command, _) =>
|
case Msg(cmd: Command, _) =>
|
||||||
datePicker ! cmd
|
datePicker ! cmd
|
||||||
stay()
|
stay()
|
||||||
case Msg(date: ZonedDateTime, bookingData: BookingData) =>
|
case Msg(date: ZonedDateTime, bookingData: BookingData) =>
|
||||||
goto(requestDayTime) using bookingData.copy(dateTo = date)
|
goto(requestAction) using bookingData.copy(dateTo = date)
|
||||||
}
|
|
||||||
|
|
||||||
private def requestDayTime: Step =
|
|
||||||
question { _ =>
|
|
||||||
bot.sendMessage(userId.source, lang.chooseTimeOfDay,
|
|
||||||
inlineKeyboard = createInlineKeyboard(lang.timeOfDay.map { case (id, label) => Button(label, id.toString) }.toSeq, columns = 1))
|
|
||||||
} answer {
|
|
||||||
case Msg(Command(_, msg, Some(timeIdStr)), bookingData: BookingData) =>
|
|
||||||
val timeId = timeIdStr.toInt
|
|
||||||
bot.sendEditMessage(userId.source, msg.messageId, lang.preferredTimeIs(timeId))
|
|
||||||
goto(requestAction) using bookingData.copy(timeOfDay = timeId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private def requestAction: Step =
|
private def requestAction: Step =
|
||||||
question { bookingData =>
|
ask { bookingData =>
|
||||||
dataService.storeAppointment(userId.accountId, bookingData)
|
dataService.storeAppointment(userId.accountId, bookingData)
|
||||||
bot.sendMessage(userId.source,
|
bot.sendMessage(userId.source,
|
||||||
lang.bookingSummary(bookingData),
|
lang.bookingSummary(bookingData),
|
||||||
inlineKeyboard = createInlineKeyboard(Seq(Button(lang.findTerms, Tags.FindTerms), Button(lang.modifyDate, Tags.ModifyDate))))
|
inlineKeyboard = createInlineKeyboard(
|
||||||
} answer {
|
Seq(Button(lang.findTerms, Tags.FindTerms), Button(lang.modifyDate, Tags.ModifyDate))
|
||||||
|
))
|
||||||
|
} onReply {
|
||||||
case Msg(CallbackCommand(Tags.FindTerms), _) =>
|
case Msg(CallbackCommand(Tags.FindTerms), _) =>
|
||||||
goto(requestTerm)
|
goto(requestTerm)
|
||||||
case Msg(CallbackCommand(Tags.ModifyDate), _) =>
|
case Msg(CallbackCommand(Tags.ModifyDate), _) =>
|
||||||
@@ -136,14 +127,14 @@ class Book(val userId: UserId, bot: Bot, apiService: ApiService, dataService: Da
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def requestTerm: Step =
|
private def requestTerm: Step =
|
||||||
question { bookingData =>
|
ask { bookingData =>
|
||||||
val availableTerms = apiService.getAvailableTerms(userId.accountId, bookingData.cityId.id,
|
val availableTerms = apiService.getAvailableTerms(userId.accountId, bookingData.cityId.id,
|
||||||
bookingData.clinicId.optionalId, bookingData.serviceId.id, bookingData.doctorId.optionalId,
|
bookingData.clinicId.optionalId, bookingData.serviceId.id, bookingData.doctorId.optionalId,
|
||||||
bookingData.dateFrom, Some(bookingData.dateTo), timeOfDay = bookingData.timeOfDay)
|
bookingData.dateFrom, Some(bookingData.dateTo), timeOfDay = bookingData.timeOfDay)
|
||||||
termsPager ! InitConversation
|
termsPager ! InitConversation
|
||||||
termsPager ! StartConversation
|
termsPager ! StartConversation
|
||||||
termsPager ! availableTerms
|
termsPager ! availableTerms
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(cmd: Command, _) =>
|
case Msg(cmd: Command, _) =>
|
||||||
termsPager ! cmd
|
termsPager ! cmd
|
||||||
stay()
|
stay()
|
||||||
@@ -163,10 +154,10 @@ class Book(val userId: UserId, bot: Bot, apiService: ApiService, dataService: Da
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def askNoTermsAction: Step =
|
private def askNoTermsAction: Step =
|
||||||
question { _ =>
|
ask { _ =>
|
||||||
bot.sendMessage(userId.source, lang.noTermsFound, inlineKeyboard =
|
bot.sendMessage(userId.source, lang.noTermsFound, inlineKeyboard =
|
||||||
createInlineKeyboard(Seq(Button(lang.modifyDate, Tags.ModifyDate), Button(lang.createMonitoring, Tags.CreateMonitoring))))
|
createInlineKeyboard(Seq(Button(lang.modifyDate, Tags.ModifyDate), Button(lang.createMonitoring, Tags.CreateMonitoring))))
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(CallbackCommand(Tags.ModifyDate), _) =>
|
case Msg(CallbackCommand(Tags.ModifyDate), _) =>
|
||||||
goto(requestDateFrom)
|
goto(requestDateFrom)
|
||||||
case Msg(CallbackCommand(Tags.CreateMonitoring), _) =>
|
case Msg(CallbackCommand(Tags.CreateMonitoring), _) =>
|
||||||
@@ -203,17 +194,17 @@ class Book(val userId: UserId, bot: Bot, apiService: ApiService, dataService: Da
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def askMonitoringOptions: Step =
|
private def askMonitoringOptions: Step =
|
||||||
question { _ =>
|
ask { _ =>
|
||||||
bot.sendMessage(userId.source, lang.chooseTypeOfMonitoring,
|
bot.sendMessage(userId.source, lang.chooseTypeOfMonitoring,
|
||||||
inlineKeyboard = createInlineKeyboard(Seq(Button(lang.bookByApplication, Tags.BookByApplication), Button(lang.bookManually, Tags.BookManually)), columns = 1))
|
inlineKeyboard = createInlineKeyboard(Seq(Button(lang.bookByApplication, Tags.BookByApplication), Button(lang.bookManually, Tags.BookManually)), columns = 1))
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(CallbackCommand(autobookStr), bookingData: BookingData) =>
|
case Msg(CallbackCommand(autobookStr), bookingData: BookingData) =>
|
||||||
val autobook = autobookStr.toBoolean
|
val autobook = autobookStr.toBoolean
|
||||||
goto(createMonitoring) using bookingData.copy(autobook = autobook)
|
goto(createMonitoring) using bookingData.copy(autobook = autobook)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def createMonitoring: Step =
|
private def createMonitoring: Step =
|
||||||
internalConfig { bookingData =>
|
process { bookingData =>
|
||||||
debug(s"Creating monitoring for $bookingData")
|
debug(s"Creating monitoring for $bookingData")
|
||||||
try {
|
try {
|
||||||
monitoringService.createMonitoring((userId -> bookingData).mapTo[Monitoring])
|
monitoringService.createMonitoring((userId -> bookingData).mapTo[Monitoring])
|
||||||
|
|||||||
@@ -40,11 +40,13 @@ class Bug(val userId: UserId, bot: Bot, dataService: DataService, bugPagerActorF
|
|||||||
|
|
||||||
private val bugPager = bugPagerActorFactory(userId, self)
|
private val bugPager = bugPagerActorFactory(userId, self)
|
||||||
|
|
||||||
|
entryPoint(askAction)
|
||||||
|
|
||||||
def askAction: Step =
|
def askAction: Step =
|
||||||
question { _ =>
|
ask { _ =>
|
||||||
bot.sendMessage(userId.source, lang.bugAction, inlineKeyboard =
|
bot.sendMessage(userId.source, lang.bugAction, inlineKeyboard =
|
||||||
createInlineKeyboard(Seq(Button(lang.createNewBug, Tags.SubmitNew), Button(lang.showSubmittedBugs, Tags.ListSubmitted))))
|
createInlineKeyboard(Seq(Button(lang.createNewBug, Tags.SubmitNew), Button(lang.showSubmittedBugs, Tags.ListSubmitted))))
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(Command(_, _, Some(Tags.SubmitNew)), _) =>
|
case Msg(Command(_, _, Some(Tags.SubmitNew)), _) =>
|
||||||
goto(askBugDescription)
|
goto(askBugDescription)
|
||||||
case Msg(Command(_, _, Some(Tags.ListSubmitted)), _) =>
|
case Msg(Command(_, _, Some(Tags.ListSubmitted)), _) =>
|
||||||
@@ -52,7 +54,7 @@ class Bug(val userId: UserId, bot: Bot, dataService: DataService, bugPagerActorF
|
|||||||
}
|
}
|
||||||
|
|
||||||
def displaySubmittedBugs: Step =
|
def displaySubmittedBugs: Step =
|
||||||
internalConfig { _ =>
|
process { _ =>
|
||||||
val bugs = dataService.getBugs(userId.userId)
|
val bugs = dataService.getBugs(userId.userId)
|
||||||
bugPager ! InitConversation
|
bugPager ! InitConversation
|
||||||
bugPager ! StartConversation
|
bugPager ! StartConversation
|
||||||
@@ -71,16 +73,14 @@ class Bug(val userId: UserId, bot: Bot, dataService: DataService, bugPagerActorF
|
|||||||
}
|
}
|
||||||
|
|
||||||
def askBugDescription: Step =
|
def askBugDescription: Step =
|
||||||
question { _ =>
|
ask { _ =>
|
||||||
bot.sendMessage(userId.source, lang.enterIssueDetails)
|
bot.sendMessage(userId.source, lang.enterIssueDetails)
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(MessageExtractors.TextCommand(details), _) =>
|
case Msg(MessageExtractors.TextCommand(details), _) =>
|
||||||
val bugId = dataService.submitBug(userId.userId, userId.source.sourceSystem.id, details)
|
val bugId = dataService.submitBug(userId.userId, userId.source.sourceSystem.id, details)
|
||||||
bot.sendMessage(userId.source, lang.bugHasBeenCreated(bugId.getOrElse(-1L)))
|
bot.sendMessage(userId.source, lang.bugHasBeenCreated(bugId.getOrElse(-1L)))
|
||||||
end()
|
end()
|
||||||
}
|
}
|
||||||
|
|
||||||
entryPoint(askAction)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object Bug {
|
object Bug {
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ class Chat(val userId: UserId, dataService: DataService, monitoringService: Moni
|
|||||||
stay()
|
stay()
|
||||||
}
|
}
|
||||||
|
|
||||||
private def actorDialogue(actor: ActorRef)(mainStateFunction: AnswerFn): Step =
|
private def actorDialogue(actor: ActorRef)(mainStateFunction: MessageProcessorFn): Step =
|
||||||
monologue {
|
monologue {
|
||||||
case event: Msg =>
|
case event: Msg =>
|
||||||
if (mainStateFunction.isDefinedAt(event)) mainStateFunction(event)
|
if (mainStateFunction.isDefinedAt(event)) mainStateFunction(event)
|
||||||
@@ -119,7 +119,7 @@ class Chat(val userId: UserId, dataService: DataService, monitoringService: Moni
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def secondaryState(actor: ActorRef): AnswerFn = {
|
private def secondaryState(actor: ActorRef): MessageProcessorFn = {
|
||||||
case Msg(cmd@TextCommand("/bug"), _) =>
|
case Msg(cmd@TextCommand("/bug"), _) =>
|
||||||
self ! cmd
|
self ! cmd
|
||||||
goto(bugChat)
|
goto(bugChat)
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class DatePicker(val userId: UserId, val bot: Bot, val localization: Localizatio
|
|||||||
entryPoint(configure)
|
entryPoint(configure)
|
||||||
|
|
||||||
def configure: Step =
|
def configure: Step =
|
||||||
externalConfig {
|
monologue {
|
||||||
case Msg(newMode: Mode, _) =>
|
case Msg(newMode: Mode, _) =>
|
||||||
mode = newMode
|
mode = newMode
|
||||||
stay()
|
stay()
|
||||||
@@ -58,13 +58,13 @@ class DatePicker(val userId: UserId, val bot: Bot, val localization: Localizatio
|
|||||||
}
|
}
|
||||||
|
|
||||||
def requestDate: Step =
|
def requestDate: Step =
|
||||||
question { initialDate =>
|
ask { initialDate =>
|
||||||
val message = mode match {
|
val message = mode match {
|
||||||
case DateFromMode => lang.chooseDateFrom
|
case DateFromMode => lang.chooseDateFrom
|
||||||
case DateToMode => lang.chooseDateTo
|
case DateToMode => lang.chooseDateTo
|
||||||
}
|
}
|
||||||
bot.sendMessage(userId.source, message, inlineKeyboard = dateButtons(initialDate))
|
bot.sendMessage(userId.source, message, inlineKeyboard = dateButtons(initialDate))
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(Command(_, msg, Some(Tags.Done)), finalDate) =>
|
case Msg(Command(_, msg, Some(Tags.Done)), finalDate) =>
|
||||||
val (message, updatedDate) = mode match {
|
val (message, updatedDate) = mode match {
|
||||||
case DateFromMode =>
|
case DateFromMode =>
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class History(val userId: UserId, bot: Bot, apiService: ApiService, val localiza
|
|||||||
entryPoint(prepareData)
|
entryPoint(prepareData)
|
||||||
|
|
||||||
def prepareData: Step =
|
def prepareData: Step =
|
||||||
internalConfig { _ =>
|
process { _ =>
|
||||||
val visits = apiService.visitsHistory(userId.accountId)
|
val visits = apiService.visitsHistory(userId.accountId)
|
||||||
historyPager ! InitConversation
|
historyPager ! InitConversation
|
||||||
historyPager ! StartConversation
|
historyPager ! StartConversation
|
||||||
|
|||||||
@@ -49,23 +49,23 @@ class Login(source: MessageSource, bot: Bot, dataService: DataService, apiServic
|
|||||||
}
|
}
|
||||||
|
|
||||||
def requestUsername: Step =
|
def requestUsername: Step =
|
||||||
question { _ =>
|
ask { _ =>
|
||||||
bot.sendMessage(source, lang.provideUsername)
|
bot.sendMessage(source, lang.provideUsername)
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(MessageExtractors.OptionalTextCommand(username), _) =>
|
case Msg(MessageExtractors.OptionalTextCommand(username), _) =>
|
||||||
goto(requestPassword) using LoginData(username = username)
|
goto(requestPassword) using LoginData(username = username)
|
||||||
}
|
}
|
||||||
|
|
||||||
def requestPassword: Step =
|
def requestPassword: Step =
|
||||||
question { _ =>
|
ask { _ =>
|
||||||
bot.sendMessage(source, lang.providePassword)
|
bot.sendMessage(source, lang.providePassword)
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(MessageExtractors.OptionalTextCommand(password), loginData: LoginData) =>
|
case Msg(MessageExtractors.OptionalTextCommand(password), loginData: LoginData) =>
|
||||||
goto(processLoginInformation) using loginData.copy(password = password.map(textEncryptor.encrypt))
|
goto(processLoginInformation) using loginData.copy(password = password.map(textEncryptor.encrypt))
|
||||||
}
|
}
|
||||||
|
|
||||||
def processLoginInformation: Step = {
|
def processLoginInformation: Step = {
|
||||||
internalConfig { case LoginData(Some(username), Some(password)) =>
|
process { case LoginData(Some(username), Some(password)) =>
|
||||||
val loginResult = apiService.login(username, password)
|
val loginResult = apiService.login(username, password)
|
||||||
loginResult match {
|
loginResult match {
|
||||||
case Left(error) =>
|
case Left(error) =>
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class Monitorings(val userId: UserId, bot: Bot, monitoringService: MonitoringSer
|
|||||||
entryPoint(prepareData)
|
entryPoint(prepareData)
|
||||||
|
|
||||||
def prepareData: Step =
|
def prepareData: Step =
|
||||||
internalConfig { _ =>
|
process { _ =>
|
||||||
val monitorings = monitoringService.getActiveMonitorings(userId.accountId)
|
val monitorings = monitoringService.getActiveMonitorings(userId.accountId)
|
||||||
monitoringsPager ! InitConversation
|
monitoringsPager ! InitConversation
|
||||||
monitoringsPager ! StartConversation
|
monitoringsPager ! StartConversation
|
||||||
@@ -62,10 +62,10 @@ class Monitorings(val userId: UserId, bot: Bot, monitoringService: MonitoringSer
|
|||||||
}
|
}
|
||||||
|
|
||||||
def askToDeactivateMonitoring: Step =
|
def askToDeactivateMonitoring: Step =
|
||||||
question { monitoring =>
|
ask { monitoring =>
|
||||||
bot.sendMessage(userId.source, lang.deactivateMonitoring(monitoring), inlineKeyboard =
|
bot.sendMessage(userId.source, lang.deactivateMonitoring(monitoring), inlineKeyboard =
|
||||||
createInlineKeyboard(Seq(Button(lang.no, Tags.No), Button(lang.yes, Tags.Yes))))
|
createInlineKeyboard(Seq(Button(lang.no, Tags.No), Button(lang.yes, Tags.Yes))))
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(Command(_, _, Some(Tags.No)), _) =>
|
case Msg(Command(_, _, Some(Tags.No)), _) =>
|
||||||
bot.sendMessage(userId.source, lang.monitoringWasNotDeactivated)
|
bot.sendMessage(userId.source, lang.monitoringWasNotDeactivated)
|
||||||
end()
|
end()
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class Pager[Data](val userId: UserId, bot: Bot, makeMessage: (Data, Int, Int) =>
|
|||||||
entryPoint(awaitForData)
|
entryPoint(awaitForData)
|
||||||
|
|
||||||
private def awaitForData: Step =
|
private def awaitForData: Step =
|
||||||
externalConfig {
|
monologue {
|
||||||
case Msg(Left(error: Throwable), _) =>
|
case Msg(Left(error: Throwable), _) =>
|
||||||
bot.sendMessage(userId.source, error.getMessage)
|
bot.sendMessage(userId.source, error.getMessage)
|
||||||
end()
|
end()
|
||||||
@@ -55,9 +55,9 @@ class Pager[Data](val userId: UserId, bot: Bot, makeMessage: (Data, Int, Int) =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def displayPage: Step =
|
private def displayPage: Step =
|
||||||
question { case (registry, massageIdMaybe) =>
|
ask { case (registry, massageIdMaybe) =>
|
||||||
sendPage(registry.page, registry.pages, massageIdMaybe)
|
sendPage(registry.page, registry.pages, massageIdMaybe)
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(Command(_, msg, Some(Tags.Next)), (registry, _)) =>
|
case Msg(Command(_, msg, Some(Tags.Next)), (registry, _)) =>
|
||||||
val page = registry.page + 1
|
val page = registry.page + 1
|
||||||
goto(displayPage) using registry.copy(page = page) -> Some(msg.messageId)
|
goto(displayPage) using registry.copy(page = page) -> Some(msg.messageId)
|
||||||
|
|||||||
@@ -37,19 +37,19 @@ class Settings(val userId: UserId, bot: Bot, dataService: DataService, val local
|
|||||||
entryPoint(askForAction)
|
entryPoint(askForAction)
|
||||||
|
|
||||||
def askForAction: Step =
|
def askForAction: Step =
|
||||||
question { _ =>
|
ask { _ =>
|
||||||
bot.sendMessage(userId.source, lang.settingsHeader, inlineKeyboard =
|
bot.sendMessage(userId.source, lang.settingsHeader, inlineKeyboard =
|
||||||
createInlineKeyboard(Seq(Button(lang.language, Tags.Language))))
|
createInlineKeyboard(Seq(Button(lang.language, Tags.Language))))
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(Command(_, _, Some(Tags.Language)), _) =>
|
case Msg(Command(_, _, Some(Tags.Language)), _) =>
|
||||||
goto(askLanguage)
|
goto(askLanguage)
|
||||||
}
|
}
|
||||||
|
|
||||||
def askLanguage: Step =
|
def askLanguage: Step =
|
||||||
question { _ =>
|
ask { _ =>
|
||||||
bot.sendMessage(userId.source, lang.chooseLanguage,
|
bot.sendMessage(userId.source, lang.chooseLanguage,
|
||||||
inlineKeyboard = createInlineKeyboard(Lang.Langs.map(l => Button(l.label, l.id)), columns = 1))
|
inlineKeyboard = createInlineKeyboard(Lang.Langs.map(l => Button(l.label, l.id)), columns = 1))
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(Command(_, _, Some(langIdStr)), _) =>
|
case Msg(Command(_, _, Some(langIdStr)), _) =>
|
||||||
val langId = langIdStr.toInt
|
val langId = langIdStr.toInt
|
||||||
localization.updateLanguage(userId.userId, Lang(langId))
|
localization.updateLanguage(userId.userId, Lang(langId))
|
||||||
|
|||||||
@@ -41,16 +41,16 @@ class StaticData(val userId: UserId, bot: Bot, val localization: Localization, o
|
|||||||
entryPoint(AwaitConfig)
|
entryPoint(AwaitConfig)
|
||||||
|
|
||||||
def AwaitConfig: Step =
|
def AwaitConfig: Step =
|
||||||
externalConfig {
|
monologue {
|
||||||
case Msg(newConfig: StaticDataConfig, _) =>
|
case Msg(newConfig: StaticDataConfig, _) =>
|
||||||
config = newConfig
|
config = newConfig
|
||||||
goto(askForLatestOption)
|
goto(askForLatestOption)
|
||||||
}
|
}
|
||||||
|
|
||||||
def askForLatestOption: Step =
|
def askForLatestOption: Step =
|
||||||
question { _ =>
|
ask { _ =>
|
||||||
originator ! LatestOptions
|
originator ! LatestOptions
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(LatestOptions(options), _) if options.isEmpty =>
|
case Msg(LatestOptions(options), _) if options.isEmpty =>
|
||||||
val callbackTags = anySelectOption
|
val callbackTags = anySelectOption
|
||||||
goto(askForUserInput) using callbackTags
|
goto(askForUserInput) using callbackTags
|
||||||
@@ -60,10 +60,10 @@ class StaticData(val userId: UserId, bot: Bot, val localization: Localization, o
|
|||||||
}
|
}
|
||||||
|
|
||||||
def askForUserInput: Step =
|
def askForUserInput: Step =
|
||||||
question { callbackTags =>
|
ask { callbackTags =>
|
||||||
bot.sendMessage(userId.source, lang.pleaseEnterStaticDataNameOrPrevious(config),
|
bot.sendMessage(userId.source, lang.pleaseEnterStaticDataNameOrPrevious(config),
|
||||||
inlineKeyboard = createInlineKeyboard(callbackTags, columns = 1))
|
inlineKeyboard = createInlineKeyboard(callbackTags, columns = 1))
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(Command(_, msg, Some(tag)), callbackTags) =>
|
case Msg(Command(_, msg, Some(tag)), callbackTags) =>
|
||||||
val id = tag.toLong
|
val id = tag.toLong
|
||||||
val label = callbackTags.find(_.tag == tag).map(_.label).getOrElse(sys.error("Unable to get callback tag label"))
|
val label = callbackTags.find(_.tag == tag).map(_.label).getOrElse(sys.error("Unable to get callback tag label"))
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ trait StaticDataForBooking extends Conversation[BookingData] {
|
|||||||
|
|
||||||
private[actor] def staticData: ActorRef
|
private[actor] def staticData: ActorRef
|
||||||
|
|
||||||
protected def withFunctions(latestOptions: => Seq[IdName], staticOptions: => Either[Throwable, List[IdName]], applyId: IdName => BookingData): Step => AnswerFn = {
|
protected def withFunctions(latestOptions: => Seq[IdName], staticOptions: => Either[Throwable, List[IdName]], applyId: IdName => BookingData): Step => MessageProcessorFn = {
|
||||||
nextStep: Step => {
|
nextStep: Step => {
|
||||||
case Msg(cmd: Command, _) =>
|
case Msg(cmd: Command, _) =>
|
||||||
staticData ! cmd
|
staticData ! cmd
|
||||||
@@ -51,12 +51,12 @@ trait StaticDataForBooking extends Conversation[BookingData] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected def staticData(staticDataConfig: => StaticDataConfig)(functions: BookingData => Step => AnswerFn)(requestNext: Step): Step = {
|
protected def staticData(staticDataConfig: => StaticDataConfig)(functions: BookingData => Step => MessageProcessorFn)(requestNext: Step): Step = {
|
||||||
question { _ =>
|
ask { _ =>
|
||||||
staticData ! InitConversation
|
staticData ! InitConversation
|
||||||
staticData ! StartConversation
|
staticData ! StartConversation
|
||||||
staticData ! staticDataConfig
|
staticData ! staticDataConfig
|
||||||
} answer {
|
} onReply {
|
||||||
case msg@Msg(_, bookingData: BookingData) =>
|
case msg@Msg(_, bookingData: BookingData) =>
|
||||||
val fn = functions(bookingData)(requestNext)
|
val fn = functions(bookingData)(requestNext)
|
||||||
fn(msg)
|
fn(msg)
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class Visits(val userId: UserId, bot: Bot, apiService: ApiService, val localizat
|
|||||||
entryPoint(prepareData)
|
entryPoint(prepareData)
|
||||||
|
|
||||||
def prepareData: Step =
|
def prepareData: Step =
|
||||||
internalConfig { _ =>
|
process { _ =>
|
||||||
val visits = apiService.reservedVisits(userId.accountId)
|
val visits = apiService.reservedVisits(userId.accountId)
|
||||||
reservedVisitsPager ! InitConversation
|
reservedVisitsPager ! InitConversation
|
||||||
reservedVisitsPager ! StartConversation
|
reservedVisitsPager ! StartConversation
|
||||||
@@ -63,10 +63,10 @@ class Visits(val userId: UserId, bot: Bot, apiService: ApiService, val localizat
|
|||||||
}
|
}
|
||||||
|
|
||||||
def askToCancelVisit: Step =
|
def askToCancelVisit: Step =
|
||||||
question { visit =>
|
ask { visit =>
|
||||||
bot.sendMessage(userId.source, lang.areYouSureToCancelAppointment(visit),
|
bot.sendMessage(userId.source, lang.areYouSureToCancelAppointment(visit),
|
||||||
inlineKeyboard = createInlineKeyboard(Seq(Button(lang.no, Tags.No), Button(lang.yes, Tags.Yes))))
|
inlineKeyboard = createInlineKeyboard(Seq(Button(lang.no, Tags.No), Button(lang.yes, Tags.Yes))))
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(Command(_, _, Some(Tags.No)), _) =>
|
case Msg(Command(_, _, Some(Tags.No)), _) =>
|
||||||
bot.sendMessage(userId.source, lang.appointmentWasNotCancelled)
|
bot.sendMessage(userId.source, lang.appointmentWasNotCancelled)
|
||||||
end()
|
end()
|
||||||
|
|||||||
@@ -15,13 +15,13 @@ trait Conversation[D] extends Actor with Domain[D] with Logger {
|
|||||||
|
|
||||||
private var startWithStep: Step = _
|
private var startWithStep: Step = _
|
||||||
|
|
||||||
private val defaultMsgHandler: AnswerFn = {
|
private val defaultMsgHandler: MessageProcessorFn = {
|
||||||
case Msg(any, data) =>
|
case Msg(any, data) =>
|
||||||
debug(s"Unhandled message received. [$any, $data]")
|
debug(s"Unhandled message received. [$any, $data]")
|
||||||
NextStep(currentStep, Some(data))
|
NextStep(currentStep, Some(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
private var msgHandler: AnswerFn = defaultMsgHandler
|
private var msgHandler: MessageProcessorFn = defaultMsgHandler
|
||||||
|
|
||||||
private var runAfterInit: () => Unit = () => {}
|
private var runAfterInit: () => Unit = () => {}
|
||||||
|
|
||||||
@@ -34,8 +34,8 @@ trait Conversation[D] extends Actor with Domain[D] with Logger {
|
|||||||
def execute(): Unit = {
|
def execute(): Unit = {
|
||||||
try {
|
try {
|
||||||
currentStep match {
|
currentStep match {
|
||||||
case qa: QuestionAnswer => qa.question.questionFn(currentData)
|
case qa: Dialogue => qa.askFn(currentData)
|
||||||
case InternalConfiguration(fn) =>
|
case Process(fn) =>
|
||||||
val nextStep = fn(currentData)
|
val nextStep = fn(currentData)
|
||||||
moveToNextStep(nextStep)
|
moveToNextStep(nextStep)
|
||||||
case _ => //do nothing
|
case _ => //do nothing
|
||||||
@@ -56,10 +56,7 @@ trait Conversation[D] extends Actor with Domain[D] with Logger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
currentStep match {
|
currentStep match {
|
||||||
case ExternalConfiguration(fn) =>
|
case Dialogue(_, fn) =>
|
||||||
val conf = Msg(any, currentData)
|
|
||||||
handle(conf, fn, msgHandler)
|
|
||||||
case QuestionAnswer(_, Answer(fn)) =>
|
|
||||||
val fact = Msg(any, currentData)
|
val fact = Msg(any, currentData)
|
||||||
handle(fact, fn, msgHandler)
|
handle(fact, fn, msgHandler)
|
||||||
case Monologue(fn) =>
|
case Monologue(fn) =>
|
||||||
@@ -87,13 +84,11 @@ trait Conversation[D] extends Actor with Domain[D] with Logger {
|
|||||||
init()
|
init()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected def monologue(answerFn: AnswerFn): Monologue = Monologue(answerFn)
|
protected def monologue(answerFn: MessageProcessorFn): Monologue = Monologue(answerFn)
|
||||||
|
|
||||||
protected def question(questionFn: D => Unit): Question = Question(questionFn)
|
protected def ask(askFn: D => Unit): Ask = Ask(askFn)
|
||||||
|
|
||||||
protected def externalConfig(receiveConfFunction: ExternalConfigFn): ExternalConfiguration = ExternalConfiguration(receiveConfFunction)
|
protected def process(processFn: ProcessFn): Process = Process(processFn)
|
||||||
|
|
||||||
protected def internalConfig(receiveConfFunction: InternalConfigFn): InternalConfiguration = InternalConfiguration(receiveConfFunction)
|
|
||||||
|
|
||||||
protected def end(): NextStep = NextStep(End)
|
protected def end(): NextStep = NextStep(End)
|
||||||
|
|
||||||
@@ -104,7 +99,7 @@ trait Conversation[D] extends Actor with Domain[D] with Logger {
|
|||||||
|
|
||||||
protected def stay(): NextStep = NextStep(currentStep)
|
protected def stay(): NextStep = NextStep(currentStep)
|
||||||
|
|
||||||
protected def whenUnhandledMsg(receiveMsgFn: AnswerFn): Unit = {
|
protected def whenUnhandledMsg(receiveMsgFn: MessageProcessorFn): Unit = {
|
||||||
msgHandler = receiveMsgFn orElse defaultMsgHandler
|
msgHandler = receiveMsgFn orElse defaultMsgHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
package com.lbs.server.actor.conversation
|
package com.lbs.server.actor.conversation
|
||||||
|
|
||||||
trait Domain[D] {
|
trait Domain[D] {
|
||||||
protected type QuestionFn = D => Unit
|
protected type AskFn = D => Unit
|
||||||
|
|
||||||
protected type AnswerFn = PartialFunction[Msg, NextStep]
|
protected type MessageProcessorFn = PartialFunction[Msg, NextStep]
|
||||||
|
|
||||||
protected type ExternalConfigFn = AnswerFn
|
protected type ProcessFn = D => NextStep
|
||||||
|
|
||||||
protected type InternalConfigFn = D => NextStep
|
|
||||||
|
|
||||||
protected case class Msg(message: Any, data: D)
|
protected case class Msg(message: Any, data: D)
|
||||||
|
|
||||||
@@ -15,22 +13,18 @@ trait Domain[D] {
|
|||||||
|
|
||||||
private[conversation] object End extends Step
|
private[conversation] object End extends Step
|
||||||
|
|
||||||
protected case class ExternalConfiguration(configFn: ExternalConfigFn) extends Step
|
protected case class Process(processFn: ProcessFn) extends Step
|
||||||
|
|
||||||
protected case class InternalConfiguration(configFn: InternalConfigFn) extends Step
|
protected case class Dialogue(askFn: AskFn, replyProcessorFn: MessageProcessorFn) extends Step
|
||||||
|
|
||||||
protected case class QuestionAnswer(question: Question, answer: Answer) extends Step
|
protected case class Monologue(replyProcessorFn: MessageProcessorFn) extends Step
|
||||||
|
|
||||||
protected case class Monologue(answerFn: AnswerFn) extends Step
|
|
||||||
|
|
||||||
private[conversation] case class NextStep(step: Step, data: Option[D] = None)
|
private[conversation] case class NextStep(step: Step, data: Option[D] = None)
|
||||||
|
|
||||||
private[conversation] case class Question(questionFn: QuestionFn)
|
private[conversation] case class Ask(askFn: AskFn)
|
||||||
|
|
||||||
private[conversation] case class Answer(answerFn: AnswerFn)
|
protected implicit class RichQuestion(ask: Ask) {
|
||||||
|
def onReply(replyProcessorFn: MessageProcessorFn): Dialogue = Dialogue(ask.askFn, replyProcessorFn)
|
||||||
protected implicit class RichQuestion(question: Question) {
|
|
||||||
def answer(answerFn: AnswerFn): QuestionAnswer = QuestionAnswer(question, Answer(answerFn))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected implicit class NextStepOps(nextStep: NextStep) {
|
protected implicit class NextStepOps(nextStep: NextStep) {
|
||||||
|
|||||||
@@ -23,32 +23,32 @@ class ConversationSpec extends AkkaTestKit {
|
|||||||
private var conf: String = _
|
private var conf: String = _
|
||||||
|
|
||||||
def configure: Step =
|
def configure: Step =
|
||||||
externalConfig {
|
monologue {
|
||||||
case Msg(confStr: String, data) =>
|
case Msg(confStr: String, data) =>
|
||||||
conf = confStr
|
conf = confStr
|
||||||
goto(askHello) using data.copy(configured = true)
|
goto(askHello) using data.copy(configured = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
def askHello: Step =
|
def askHello: Step =
|
||||||
question { data =>
|
ask { data =>
|
||||||
self ! Hello
|
self ! Hello
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(Hello, data) =>
|
case Msg(Hello, data) =>
|
||||||
goto(askWorld) using data.copy(hello = "hello")
|
goto(askWorld) using data.copy(hello = "hello")
|
||||||
}
|
}
|
||||||
|
|
||||||
def askWorld: Step =
|
def askWorld: Step =
|
||||||
question { data =>
|
ask { data =>
|
||||||
self ! World
|
self ! World
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(World, data) =>
|
case Msg(World, data) =>
|
||||||
goto(askDialogue) using data.copy(world = "world")
|
goto(askDialogue) using data.copy(world = "world")
|
||||||
}
|
}
|
||||||
|
|
||||||
def askDialogue: Step =
|
def askDialogue: Step =
|
||||||
question { data =>
|
ask { data =>
|
||||||
self ! Dialogue
|
self ! Dialogue
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(Dialogue, data) =>
|
case Msg(Dialogue, data) =>
|
||||||
originator ! data.copy(people = "dialogue") -> conf
|
originator ! data.copy(people = "dialogue") -> conf
|
||||||
end()
|
end()
|
||||||
@@ -81,19 +81,19 @@ class ConversationSpec extends AkkaTestKit {
|
|||||||
class TestActor(originator: ActorRef) extends Conversation[Data] {
|
class TestActor(originator: ActorRef) extends Conversation[Data] {
|
||||||
|
|
||||||
def configure1: Step =
|
def configure1: Step =
|
||||||
internalConfig { _ =>
|
process { _ =>
|
||||||
goto(configure2) using Data(configured = true)
|
goto(configure2) using Data(configured = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
def configure2: Step =
|
def configure2: Step =
|
||||||
internalConfig { data =>
|
process { data =>
|
||||||
goto(askMessage2) using data.copy(message1 = "hello")
|
goto(askMessage2) using data.copy(message1 = "hello")
|
||||||
}
|
}
|
||||||
|
|
||||||
def askMessage2: Step =
|
def askMessage2: Step =
|
||||||
question { _ =>
|
ask { _ =>
|
||||||
self ! InvokeEnrichMessage
|
self ! InvokeEnrichMessage
|
||||||
} answer {
|
} onReply {
|
||||||
case Msg(InvokeEnrichMessage, data) =>
|
case Msg(InvokeEnrichMessage, data) =>
|
||||||
originator ! data.copy(message2 = "world")
|
originator ! data.copy(message2 = "world")
|
||||||
end()
|
end()
|
||||||
|
|||||||
Reference in New Issue
Block a user