Added list method and fixed some errors during parsing of czech post json response

This commit is contained in:
Pavel Kachalouski
2018-10-28 19:18:14 +01:00
parent 1ddefef6a6
commit 802da93db8
3 changed files with 55 additions and 12 deletions

View File

@@ -61,7 +61,8 @@ object CheckDeliveryDialog {
sendMessage("Please enter parcel ID.", waitParcelId(parcelId => addParcel(parcelId)), initial) sendMessage("Please enter parcel ID.", waitParcelId(parcelId => addParcel(parcelId)), initial)
case RemoveParcel => case RemoveParcel =>
sendMessage("Please enter parcel ID.", waitParcelId(parcelId => removeParcel(parcelId)), initial) sendMessage("Please enter parcel ID.", waitParcelId(parcelId => removeParcel(parcelId)), initial)
case ListParcels => sendMessage("This command is not supported yet.", initial, initial) case ListParcels =>
listParcels
case Help => case Help =>
sendMessage("Supported commands: /add, /remove, /list, /help", initial, initial) sendMessage("Supported commands: /add, /remove, /list, /help", initial, initial)
case DeliveryStateChanged(state) => case DeliveryStateChanged(state) =>
@@ -98,6 +99,28 @@ object CheckDeliveryDialog {
} }
} }
def listParcels: Behavior[Command] = Behaviors.setup { ctx =>
case class ListParcelsSuccess(parcelsList: String) extends Command
case class ListParcelsFailure(exception: Throwable) extends Command
implicit val timeout: Timeout = 5.seconds
ctx.ask[CzechPostDeliveryCheck.Command, CzechPostDeliveryCheck.ListParcelsResult](czechPostDeliveryCheck)(ref => CzechPostDeliveryCheck.ListParcels(ref)) {
case Success(CzechPostDeliveryCheck.ListParcelsResult(parcelsList)) => ListParcelsSuccess(parcelsList)
case Failure(exception) => ListParcelsFailure(exception)
}
Behaviors.receiveMessage {
case ListParcelsSuccess(parcelsList) =>
sendMessage(parcelsList, initial, initial)
case ListParcelsFailure(exception) =>
ctx.log.error(exception, "action=list_parcels result=failure chat_id={}", chatId)
sendMessage("Failed to get list of the your watched parcels. Please try again later.", initial, initial)
case otherMessage =>
stashBuffer.stash(otherMessage)
Behaviors.same
}
}
def removeParcel(parcelId: String): Behavior[Command] = Behaviors.setup { ctx => def removeParcel(parcelId: String): Behavior[Command] = Behaviors.setup { ctx =>
case object RemoveParcelSuccess extends Command case object RemoveParcelSuccess extends Command
case class RemoveParcelFailure(exception: Throwable) extends Command case class RemoveParcelFailure(exception: Throwable) extends Command

View File

@@ -38,7 +38,7 @@ object Entities {
text: String, text: String,
postcode: Option[String], postcode: Option[String],
postoffice: Option[String], postoffice: Option[String],
idIcon: Option[String], idIcon: Option[Int],
publicAccess: Int, publicAccess: Int,
latitude: Option[Double], latitude: Option[Double],
longitude: Option[Double], longitude: Option[Double],
@@ -58,12 +58,12 @@ object CzechPostDeliveryCheck {
sealed trait CommandResult sealed trait CommandResult
sealed trait Event sealed trait Event
case class ParcelState(attributes: Option[Entities.Attributes] = None, states: Set[Entities.State] = Set.empty) { case class ParcelState(attributes: Option[Entities.Attributes] = None, states: Set[Entities.State] = Set.empty) {
def prettyPrint: String = { def prettyPrint(parcelId: String): String = {
val statesString = states val statesString = states
.map(state => s"${state.prettyPrint}\n===========================\n") .map(state => s"${state.prettyPrint}\n===========================\n")
.mkString .mkString
s"""|*New state(s):* s"""|*New state(s) of the parcel $parcelId:*
|=========================== |===========================
|$statesString""".stripMargin |$statesString""".stripMargin
} }
@@ -72,6 +72,8 @@ object CzechPostDeliveryCheck {
case class AddParcel(parcelId: String, replyTo: ActorRef[CommandResult]) extends Command case class AddParcel(parcelId: String, replyTo: ActorRef[CommandResult]) extends Command
case class RemoveParcel(parcelId: String, replyTo: ActorRef[CommandResult]) extends Command case class RemoveParcel(parcelId: String, replyTo: ActorRef[CommandResult]) extends Command
case class ListParcels(replyTo: ActorRef[ListParcelsResult]) extends Command
case class ListParcelsResult(parcelsList: String)
case object CommandResultSuccess extends CommandResult case object CommandResultSuccess extends CommandResult
case class CommandResultFailure(exception: Throwable) extends CommandResult case class CommandResultFailure(exception: Throwable) extends CommandResult
@@ -154,13 +156,21 @@ object CzechPostDeliveryCheck {
.thenRun(_ => replyTo ! CommandResultFailure(ParcelIdNotFound(parcelId))) .thenRun(_ => replyTo ! CommandResultFailure(ParcelIdNotFound(parcelId)))
} }
case ListParcels(replyTo) =>
val parcelsList = "*List of your watched parcels:*\n" + (if (state.parcelStates.keys.nonEmpty) state.parcelStates.keys.toSeq.sorted.map(id => id + "\n").mkString else "(empty)")
Effect.none
.thenRun(_ => replyTo ! ListParcelsResult(parcelsList))
case CheckParcels => case CheckParcels =>
ctx.log.info("action=check_parcel_state chat_id={}", chatId)
val parcelIds = state.parcelStates.keys.grouped(10).map(ids => ids.foldLeft("")((acc, id) => if (acc.isEmpty) id else s"$acc;$id")) val parcelIds = state.parcelStates.keys.grouped(10).map(ids => ids.foldLeft("")((acc, id) => if (acc.isEmpty) id else s"$acc;$id"))
for (ids <- parcelIds) { for (ids <- parcelIds) {
val checkUri = Uri(s"https://b2c.cpost.cz/services/ParcelHistory/getDataAsJson?idParcel=$ids&language=en") val checkUri = Uri(s"https://b2c.cpost.cz/services/ParcelHistory/getDataAsJson?idParcel=$ids&language=en")
val request = HttpRequest(uri = checkUri, headers = immutable.Seq(Accept(MediaTypes.`application/json`))) val request = HttpRequest(uri = checkUri, headers = immutable.Seq(Accept(MediaTypes.`application/json`)))
ctx.log.info("action=check_parcel_state chat_id={} check_uri={}", chatId, checkUri)
http http
.singleRequest(request, connectionContext = sslContext, settings = connectionSettings) .singleRequest(request, connectionContext = sslContext, settings = connectionSettings)
.transform { .transform {
@@ -174,6 +184,10 @@ object CzechPostDeliveryCheck {
case Failure(exception) => case Failure(exception) =>
ctx.log.error(exception, "Error checking parcel history.") ctx.log.error(exception, "Error checking parcel history.")
} }
.andThen {
case Success(_) => ctx.log.info("action=check_parcel_state result=success chat_id={} check_uri={}", chatId, checkUri)
case Failure(exception) => ctx.log.error(exception, "action=check_parcel_state result=failure chat_id={} check_uri={}", chatId, checkUri)
}
} }
Effect.none Effect.none
@@ -194,7 +208,7 @@ object CzechPostDeliveryCheck {
.persist(attributesChangedEvent ++ stateEvents) .persist(attributesChangedEvent ++ stateEvents)
.thenRun(_ => { .thenRun(_ => {
if (newStates.nonEmpty) { if (newStates.nonEmpty) {
stateReporter ! DeliveryStateChanged(ParcelState(None, newStates).prettyPrint) stateReporter ! DeliveryStateChanged(ParcelState(None, newStates).prettyPrint(parcelId))
} }
}) })
} }

View File

@@ -11,7 +11,7 @@ import akka.actor.typed.scaladsl.{Behaviors, StashBuffer}
import akka.actor.typed.{ActorRef, Behavior, DispatcherSelector} import akka.actor.typed.{ActorRef, Behavior, DispatcherSelector}
import akka.http.scaladsl.marshalling.Marshal import akka.http.scaladsl.marshalling.Marshal
import akka.http.scaladsl.model._ import akka.http.scaladsl.model._
import akka.http.scaladsl.server.Directives.{as, entity, onComplete, path, post, complete} import akka.http.scaladsl.server.Directives.{as, entity, onComplete, path, post, complete, extractLog}
import akka.http.scaladsl.server.Route import akka.http.scaladsl.server.Route
import akka.http.scaladsl.{ConnectionContext, Http, HttpExt, HttpsConnectionContext} import akka.http.scaladsl.{ConnectionContext, Http, HttpExt, HttpsConnectionContext}
import akka.stream.ActorMaterializer import akka.stream.ActorMaterializer
@@ -202,13 +202,19 @@ object TelegramBot {
path(hookId) { path(hookId) {
post { post {
entity(as[Update]) { update => extractLog { log =>
onComplete(updatesProcessor.?[DialogManager.CommandResult](ref => DialogManager.ProcessUpdate(update, ref))) { entity(as[Update]) { update =>
case Success(processResult) => processResult match { onComplete(updatesProcessor.?[DialogManager.CommandResult](ref => DialogManager.ProcessUpdate(update, ref))) {
case DialogManager.ProcessUpdateSuccess => complete(HttpResponse(status = StatusCodes.OK)) case Success(processResult) => processResult match {
case DialogManager.ProcessUpdateFailure(exception) => complete(HttpResponse(status = StatusCodes.InternalServerError)) case DialogManager.ProcessUpdateSuccess => complete(HttpResponse(status = StatusCodes.OK))
case DialogManager.ProcessUpdateFailure(exception) =>
log.error(exception, "action=process_update result=failure message={}", update)
complete(HttpResponse(status = StatusCodes.InternalServerError))
}
case Failure(exception) =>
log.error(exception, "action=process_update result=failure message={}", update)
complete(HttpResponse(status = StatusCodes.InternalServerError))
} }
case Failure(exception) => complete(HttpResponse(status = StatusCodes.InternalServerError))
} }
} }
} }