mirror of
https://github.com/dyrkin/luxmed-bot.git
synced 2025-12-21 13:23:05 +01:00
abstracted luxmed api over cats monad error
This commit is contained in:
@@ -4,18 +4,21 @@ package com.lbs.api
|
|||||||
import java.time.ZonedDateTime
|
import java.time.ZonedDateTime
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
|
import cats.implicits.toFunctorOps
|
||||||
import com.lbs.api.ApiResponseMutators._
|
import com.lbs.api.ApiResponseMutators._
|
||||||
import com.lbs.api.http._
|
import com.lbs.api.http._
|
||||||
import com.lbs.api.http.headers._
|
import com.lbs.api.http.headers._
|
||||||
import com.lbs.api.json.JsonSerializer.extensions._
|
import com.lbs.api.json.JsonSerializer.extensions._
|
||||||
import com.lbs.api.json.model._
|
import com.lbs.api.json.model.{AvailableTermsResponse, ReservationFilterResponse, ReservedVisitsResponse, VisitsHistoryResponse, _}
|
||||||
import scalaj.http.{HttpRequest, HttpResponse}
|
import scalaj.http.{HttpRequest, HttpResponse}
|
||||||
|
|
||||||
object LuxmedApi extends ApiBase {
|
import scala.language.higherKinds
|
||||||
|
|
||||||
|
class LuxmedApi[F[_] : ThrowableMonad] extends ApiBase {
|
||||||
|
|
||||||
private val dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
|
private val dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
|
||||||
|
|
||||||
def login(username: String, password: String, clientId: String = "iPhone"): Either[Throwable, LoginResponse] = {
|
def login(username: String, password: String, clientId: String = "iPhone"): F[LoginResponse] = {
|
||||||
val request = http("token").
|
val request = http("token").
|
||||||
header(`Content-Type`, "application/x-www-form-urlencoded").
|
header(`Content-Type`, "application/x-www-form-urlencoded").
|
||||||
header(`x-api-client-identifier`, clientId).
|
header(`x-api-client-identifier`, clientId).
|
||||||
@@ -26,7 +29,7 @@ object LuxmedApi extends ApiBase {
|
|||||||
post[LoginResponse](request)
|
post[LoginResponse](request)
|
||||||
}
|
}
|
||||||
|
|
||||||
def refreshToken(refreshToken: String, clientId: String = "iPhone"): Either[Throwable, LoginResponse] = {
|
def refreshToken(refreshToken: String, clientId: String = "iPhone"): F[LoginResponse] = {
|
||||||
val request = http("token").
|
val request = http("token").
|
||||||
header(`Content-Type`, "application/x-www-form-urlencoded").
|
header(`Content-Type`, "application/x-www-form-urlencoded").
|
||||||
header(`x-api-client-identifier`, clientId).
|
header(`x-api-client-identifier`, clientId).
|
||||||
@@ -37,7 +40,7 @@ object LuxmedApi extends ApiBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def reservedVisits(accessToken: String, tokenType: String, fromDate: ZonedDateTime = ZonedDateTime.now(),
|
def reservedVisits(accessToken: String, tokenType: String, fromDate: ZonedDateTime = ZonedDateTime.now(),
|
||||||
toDate: ZonedDateTime = ZonedDateTime.now().plusMonths(3)): Either[Throwable, ReservedVisitsResponse] = {
|
toDate: ZonedDateTime = ZonedDateTime.now().plusMonths(3)): F[ReservedVisitsResponse] = {
|
||||||
val request = http("visits/reserved").
|
val request = http("visits/reserved").
|
||||||
header(`Content-Type`, "application/json").
|
header(`Content-Type`, "application/json").
|
||||||
header(Authorization, s"$tokenType $accessToken").
|
header(Authorization, s"$tokenType $accessToken").
|
||||||
@@ -47,7 +50,7 @@ object LuxmedApi extends ApiBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def visitsHistory(accessToken: String, tokenType: String, fromDate: ZonedDateTime = ZonedDateTime.now().minusYears(1),
|
def visitsHistory(accessToken: String, tokenType: String, fromDate: ZonedDateTime = ZonedDateTime.now().minusYears(1),
|
||||||
toDate: ZonedDateTime = ZonedDateTime.now(), page: Int = 1, pageSize: Int = 100): Either[Throwable, VisitsHistoryResponse] = {
|
toDate: ZonedDateTime = ZonedDateTime.now(), page: Int = 1, pageSize: Int = 100): F[VisitsHistoryResponse] = {
|
||||||
val request = http("visits/history").
|
val request = http("visits/history").
|
||||||
header(`Content-Type`, "application/json").
|
header(`Content-Type`, "application/json").
|
||||||
header(Authorization, s"$tokenType $accessToken").
|
header(Authorization, s"$tokenType $accessToken").
|
||||||
@@ -60,7 +63,7 @@ object LuxmedApi extends ApiBase {
|
|||||||
|
|
||||||
def reservationFilter(accessToken: String, tokenType: String, fromDate: ZonedDateTime = ZonedDateTime.now(),
|
def reservationFilter(accessToken: String, tokenType: String, fromDate: ZonedDateTime = ZonedDateTime.now(),
|
||||||
toDate: Option[ZonedDateTime] = None, cityId: Option[Long] = None, clinicId: Option[Long] = None,
|
toDate: Option[ZonedDateTime] = None, cityId: Option[Long] = None, clinicId: Option[Long] = None,
|
||||||
serviceId: Option[Long] = None): Either[Throwable, ReservationFilterResponse] = {
|
serviceId: Option[Long] = None): F[ReservationFilterResponse] = {
|
||||||
val request = http("visits/available-terms/reservation-filter").
|
val request = http("visits/available-terms/reservation-filter").
|
||||||
header(`Content-Type`, "application/json").
|
header(`Content-Type`, "application/json").
|
||||||
header(Authorization, s"$tokenType $accessToken").
|
header(Authorization, s"$tokenType $accessToken").
|
||||||
@@ -74,7 +77,7 @@ object LuxmedApi extends ApiBase {
|
|||||||
|
|
||||||
def availableTerms(accessToken: String, tokenType: String, payerId: Long, cityId: Long, clinicId: Option[Long], serviceId: Long, doctorId: Option[Long],
|
def availableTerms(accessToken: String, tokenType: String, payerId: Long, cityId: Long, clinicId: Option[Long], serviceId: Long, doctorId: Option[Long],
|
||||||
fromDate: ZonedDateTime = ZonedDateTime.now(), toDate: Option[ZonedDateTime] = None, timeOfDay: Int = 0,
|
fromDate: ZonedDateTime = ZonedDateTime.now(), toDate: Option[ZonedDateTime] = None, timeOfDay: Int = 0,
|
||||||
languageId: Long = 10, findFirstFreeTerm: Boolean = false): Either[Throwable, AvailableTermsResponse] = {
|
languageId: Long = 10, findFirstFreeTerm: Boolean = false): F[AvailableTermsResponse] = {
|
||||||
val request = http("visits/available-terms").
|
val request = http("visits/available-terms").
|
||||||
header(`Content-Type`, "application/json").
|
header(`Content-Type`, "application/json").
|
||||||
header(Authorization, s"$tokenType $accessToken").
|
header(Authorization, s"$tokenType $accessToken").
|
||||||
@@ -91,35 +94,35 @@ object LuxmedApi extends ApiBase {
|
|||||||
get[AvailableTermsResponse](request).mutate
|
get[AvailableTermsResponse](request).mutate
|
||||||
}
|
}
|
||||||
|
|
||||||
def temporaryReservation(accessToken: String, tokenType: String, temporaryReservationRequest: TemporaryReservationRequest): Either[Throwable, TemporaryReservationResponse] = {
|
def temporaryReservation(accessToken: String, tokenType: String, temporaryReservationRequest: TemporaryReservationRequest): F[TemporaryReservationResponse] = {
|
||||||
val request = http("visits/temporary-reservation").
|
val request = http("visits/temporary-reservation").
|
||||||
header(`Content-Type`, "application/json").
|
header(`Content-Type`, "application/json").
|
||||||
header(Authorization, s"$tokenType $accessToken")
|
header(Authorization, s"$tokenType $accessToken")
|
||||||
post[TemporaryReservationResponse](request, bodyOpt = Some(temporaryReservationRequest))
|
post[TemporaryReservationResponse](request, bodyOpt = Some(temporaryReservationRequest))
|
||||||
}
|
}
|
||||||
|
|
||||||
def deleteTemporaryReservation(accessToken: String, tokenType: String, temporaryReservationId: Long): Either[Throwable, HttpResponse[String]] = {
|
def deleteTemporaryReservation(accessToken: String, tokenType: String, temporaryReservationId: Long): F[HttpResponse[String]] = {
|
||||||
val request = http(s"visits/temporary-reservation/$temporaryReservationId").
|
val request = http(s"visits/temporary-reservation/$temporaryReservationId").
|
||||||
header(`Content-Type`, "application/json").
|
header(`Content-Type`, "application/json").
|
||||||
header(Authorization, s"$tokenType $accessToken")
|
header(Authorization, s"$tokenType $accessToken")
|
||||||
delete(request)
|
delete(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
def valuations(accessToken: String, tokenType: String, valuationsRequest: ValuationsRequest): Either[Throwable, ValuationsResponse] = {
|
def valuations(accessToken: String, tokenType: String, valuationsRequest: ValuationsRequest): F[ValuationsResponse] = {
|
||||||
val request = http("visits/available-terms/valuations").
|
val request = http("visits/available-terms/valuations").
|
||||||
header(`Content-Type`, "application/json").
|
header(`Content-Type`, "application/json").
|
||||||
header(Authorization, s"$tokenType $accessToken")
|
header(Authorization, s"$tokenType $accessToken")
|
||||||
post[ValuationsResponse](request, bodyOpt = Some(valuationsRequest))
|
post[ValuationsResponse](request, bodyOpt = Some(valuationsRequest))
|
||||||
}
|
}
|
||||||
|
|
||||||
def reservation(accessToken: String, tokenType: String, reservationRequest: ReservationRequest): Either[Throwable, ReservationResponse] = {
|
def reservation(accessToken: String, tokenType: String, reservationRequest: ReservationRequest): F[ReservationResponse] = {
|
||||||
val request = http("visits/reserved").
|
val request = http("visits/reserved").
|
||||||
header(`Content-Type`, "application/json").
|
header(`Content-Type`, "application/json").
|
||||||
header(Authorization, s"$tokenType $accessToken")
|
header(Authorization, s"$tokenType $accessToken")
|
||||||
post[ReservationResponse](request, bodyOpt = Some(reservationRequest))
|
post[ReservationResponse](request, bodyOpt = Some(reservationRequest))
|
||||||
}
|
}
|
||||||
|
|
||||||
def deleteReservation(accessToken: String, tokenType: String, reservationId: Long): Either[Throwable, HttpResponse[String]] = {
|
def deleteReservation(accessToken: String, tokenType: String, reservationId: Long): F[HttpResponse[String]] = {
|
||||||
val request = http(s"visits/reserved/$reservationId").
|
val request = http(s"visits/reserved/$reservationId").
|
||||||
header(`Content-Type`, "application/json").
|
header(`Content-Type`, "application/json").
|
||||||
header(Authorization, s"$tokenType $accessToken")
|
header(Authorization, s"$tokenType $accessToken")
|
||||||
@@ -127,63 +130,63 @@ object LuxmedApi extends ApiBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//204 means OK?
|
//204 means OK?
|
||||||
def canTermBeChanged(accessToken: String, tokenType: String, reservationId: Long): Either[Throwable, HttpResponse[String]] = {
|
def canTermBeChanged(accessToken: String, tokenType: String, reservationId: Long): F[HttpResponse[String]] = {
|
||||||
val request = http(s"visits/reserved/$reservationId/can-term-be-changed").
|
val request = http(s"visits/reserved/$reservationId/can-term-be-changed").
|
||||||
header(`Content-Type`, "application/json").
|
header(`Content-Type`, "application/json").
|
||||||
header(Authorization, s"$tokenType $accessToken")
|
header(Authorization, s"$tokenType $accessToken")
|
||||||
request.toEither
|
request.invoke
|
||||||
}
|
}
|
||||||
|
|
||||||
def detailToChangeTerm(accessToken: String, tokenType: String, reservationId: Long): Either[Throwable, ChangeTermDetailsResponse] = {
|
def detailToChangeTerm(accessToken: String, tokenType: String, reservationId: Long): F[ChangeTermDetailsResponse] = {
|
||||||
val request = http(s"visits/reserved/$reservationId/details-to-change-term").
|
val request = http(s"visits/reserved/$reservationId/details-to-change-term").
|
||||||
header(`Content-Type`, "application/json").
|
header(`Content-Type`, "application/json").
|
||||||
header(Authorization, s"$tokenType $accessToken")
|
header(Authorization, s"$tokenType $accessToken")
|
||||||
get[ChangeTermDetailsResponse](request)
|
get[ChangeTermDetailsResponse](request)
|
||||||
}
|
}
|
||||||
|
|
||||||
def temporaryReservationToChangeTerm(accessToken: String, tokenType: String, reservationId: Long, temporaryReservationRequest: TemporaryReservationRequest): Either[Throwable, TemporaryReservationResponse] = {
|
def temporaryReservationToChangeTerm(accessToken: String, tokenType: String, reservationId: Long, temporaryReservationRequest: TemporaryReservationRequest): F[TemporaryReservationResponse] = {
|
||||||
val request = http(s"visits/reserved/$reservationId/temporary-reservation-to-change-term").
|
val request = http(s"visits/reserved/$reservationId/temporary-reservation-to-change-term").
|
||||||
header(`Content-Type`, "application/json").
|
header(`Content-Type`, "application/json").
|
||||||
header(Authorization, s"$tokenType $accessToken")
|
header(Authorization, s"$tokenType $accessToken")
|
||||||
post[TemporaryReservationResponse](request, bodyOpt = Some(temporaryReservationRequest))
|
post[TemporaryReservationResponse](request, bodyOpt = Some(temporaryReservationRequest))
|
||||||
}
|
}
|
||||||
|
|
||||||
def valuationToChangeTerm(accessToken: String, tokenType: String, reservationId: Long, valuationsRequest: ValuationsRequest): Either[Throwable, ValuationsResponse] = {
|
def valuationToChangeTerm(accessToken: String, tokenType: String, reservationId: Long, valuationsRequest: ValuationsRequest): F[ValuationsResponse] = {
|
||||||
val request = http(s"visits/reserved/$reservationId/valuations-to-change-term").
|
val request = http(s"visits/reserved/$reservationId/valuations-to-change-term").
|
||||||
header(`Content-Type`, "application/json").
|
header(`Content-Type`, "application/json").
|
||||||
header(Authorization, s"$tokenType $accessToken")
|
header(Authorization, s"$tokenType $accessToken")
|
||||||
post[ValuationsResponse](request, bodyOpt = Some(valuationsRequest))
|
post[ValuationsResponse](request, bodyOpt = Some(valuationsRequest))
|
||||||
}
|
}
|
||||||
|
|
||||||
def changeTerm(accessToken: String, tokenType: String, reservationId: Long, reservationRequest: ReservationRequest): Either[Throwable, ChangeTermResponse] = {
|
def changeTerm(accessToken: String, tokenType: String, reservationId: Long, reservationRequest: ReservationRequest): F[ChangeTermResponse] = {
|
||||||
val request = http(s"visits/reserved/$reservationId/term").
|
val request = http(s"visits/reserved/$reservationId/term").
|
||||||
header(`Content-Type`, "application/json").
|
header(`Content-Type`, "application/json").
|
||||||
header(Authorization, s"$tokenType $accessToken")
|
header(Authorization, s"$tokenType $accessToken")
|
||||||
put[ChangeTermResponse](request, bodyOpt = Some(reservationRequest))
|
put[ChangeTermResponse](request, bodyOpt = Some(reservationRequest))
|
||||||
}
|
}
|
||||||
|
|
||||||
private def get[T <: SerializableJsonObject](request: HttpRequest)(implicit mf: scala.reflect.Manifest[T]): Either[Throwable, T] = {
|
private def get[T <: SerializableJsonObject](request: HttpRequest)(implicit mf: scala.reflect.Manifest[T]): F[T] = {
|
||||||
request.toEither.map(_.body.as[T])
|
request.invoke.map(_.body.as[T])
|
||||||
}
|
}
|
||||||
|
|
||||||
private def post[T <: SerializableJsonObject](request: HttpRequest, bodyOpt: Option[SerializableJsonObject] = None)(implicit mf: scala.reflect.Manifest[T]): Either[Throwable, T] = {
|
private def post[T <: SerializableJsonObject](request: HttpRequest, bodyOpt: Option[SerializableJsonObject] = None)(implicit mf: scala.reflect.Manifest[T]): F[T] = {
|
||||||
val postRequest = bodyOpt match {
|
val postRequest = bodyOpt match {
|
||||||
case Some(body) => request.postData(body.asJson)
|
case Some(body) => request.postData(body.asJson)
|
||||||
case None => request.postForm
|
case None => request.postForm
|
||||||
}
|
}
|
||||||
postRequest.toEither.map(_.body.as[T])
|
postRequest.invoke.map(_.body.as[T])
|
||||||
}
|
}
|
||||||
|
|
||||||
private def put[T <: SerializableJsonObject](request: HttpRequest, bodyOpt: Option[SerializableJsonObject] = None)(implicit mf: scala.reflect.Manifest[T]): Either[Throwable, T] = {
|
private def put[T <: SerializableJsonObject](request: HttpRequest, bodyOpt: Option[SerializableJsonObject] = None)(implicit mf: scala.reflect.Manifest[T]): F[T] = {
|
||||||
val putRequest = bodyOpt match {
|
val putRequest = bodyOpt match {
|
||||||
case Some(body) => request.put(body.asJson)
|
case Some(body) => request.put(body.asJson)
|
||||||
case None => request.method("PUT")
|
case None => request.method("PUT")
|
||||||
}
|
}
|
||||||
putRequest.toEither.map(_.body.as[T])
|
putRequest.invoke.map(_.body.as[T])
|
||||||
}
|
}
|
||||||
|
|
||||||
private def delete(request: HttpRequest): Either[Throwable, HttpResponse[String]] = {
|
private def delete(request: HttpRequest): F[HttpResponse[String]] = {
|
||||||
request.postForm.method("DELETE").toEither
|
request.postForm.method("DELETE").invoke
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
package com.lbs.api.exception
|
package com.lbs.api.exception
|
||||||
|
|
||||||
class GenericException(val code: Int, val status: String, val message: String) extends ApiException(message) {
|
case class GenericException(code: Int, message: String) extends ApiException(message) {
|
||||||
override def toString: String = s"Code: $code, status: $status, message: $message"
|
override def toString: String = s"Code: $code, message: $message"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
|
|
||||||
package com.lbs.api
|
package com.lbs.api
|
||||||
|
|
||||||
import com.lbs.api.exception.{ApiException, GenericException, InvalidLoginOrPasswordException, ServiceIsAlreadyBookedException, SessionExpiredException}
|
import cats.MonadError
|
||||||
|
import cats.implicits._
|
||||||
|
import com.lbs.api.exception._
|
||||||
import com.lbs.api.json.JsonSerializer.extensions._
|
import com.lbs.api.json.JsonSerializer.extensions._
|
||||||
import com.lbs.api.json.model._
|
import com.lbs.api.json.model._
|
||||||
import com.lbs.common.Logger
|
import com.lbs.common.Logger
|
||||||
import scalaj.http.{HttpRequest, HttpResponse}
|
import scalaj.http.{HttpRequest, HttpResponse}
|
||||||
|
|
||||||
import scala.concurrent.{ExecutionContext, Future}
|
import scala.language.higherKinds
|
||||||
import scala.util.{Failure, Try}
|
import scala.util.{Failure, Success, Try}
|
||||||
|
|
||||||
package object http extends Logger {
|
package object http extends Logger {
|
||||||
|
|
||||||
@@ -29,25 +31,25 @@ package object http extends Logger {
|
|||||||
def asEntity[T <: SerializableJsonObject](implicit mf: scala.reflect.Manifest[T]): HttpResponse[T] = {
|
def asEntity[T <: SerializableJsonObject](implicit mf: scala.reflect.Manifest[T]): HttpResponse[T] = {
|
||||||
httpResponse.copy(body = httpResponse.body.as[T])
|
httpResponse.copy(body = httpResponse.body.as[T])
|
||||||
}
|
}
|
||||||
|
|
||||||
def asEntityAsync[T <: SerializableJsonObject](implicit mf: scala.reflect.Manifest[T], ec: ExecutionContext): Future[HttpResponse[T]] = {
|
|
||||||
Future(asEntity[T])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class ExtendedHttpRequest(httpRequest: HttpRequest) {
|
implicit class ExtendedHttpRequest[F[_] : ThrowableMonad](httpRequest: HttpRequest) {
|
||||||
|
def invoke: F[HttpResponse[String]] = {
|
||||||
def toEither: Either[Throwable, HttpResponse[String]] = {
|
val me = MonadError[F, Throwable]
|
||||||
toTry.toEither
|
|
||||||
}
|
|
||||||
|
|
||||||
def toTry: Try[HttpResponse[String]] = {
|
|
||||||
debug(s"Sending request:\n${hidePasswords(httpRequest)}")
|
debug(s"Sending request:\n${hidePasswords(httpRequest)}")
|
||||||
val httpResponse = Try(httpRequest.asString)
|
val httpResponse = me.pure(httpRequest.asString)
|
||||||
debug(s"Received response:\n$httpResponse")
|
debug(s"Received response:\n$httpResponse")
|
||||||
extractLuxmedError(httpResponse) match {
|
|
||||||
case Some(error) => Failure(error)
|
httpResponse.flatMap { response =>
|
||||||
case None => httpResponse.map(_.throwError)
|
val errorMaybe = extractLuxmedError(response)
|
||||||
|
errorMaybe match {
|
||||||
|
case Some(error) => me.raiseError(error)
|
||||||
|
case None =>
|
||||||
|
Try(response.throwError) match {
|
||||||
|
case Failure(error) => me.raiseError(error)
|
||||||
|
case Success(value) => me.pure(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,8 +57,8 @@ package object http extends Logger {
|
|||||||
value.map(v => httpRequest.param(key, v)).getOrElse(httpRequest)
|
value.map(v => httpRequest.param(key, v)).getOrElse(httpRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def luxmedErrorToApiException[T <: LuxmedBaseError](ler: HttpResponse[T]): ApiException = {
|
private def luxmedErrorToApiException[T <: LuxmedBaseError](code: Int, error: T): ApiException = {
|
||||||
val message = ler.body.message
|
val message = error.message
|
||||||
val errorMessage = message.toLowerCase
|
val errorMessage = message.toLowerCase
|
||||||
if (errorMessage.contains("invalid login or password"))
|
if (errorMessage.contains("invalid login or password"))
|
||||||
new InvalidLoginOrPasswordException
|
new InvalidLoginOrPasswordException
|
||||||
@@ -65,16 +67,17 @@ package object http extends Logger {
|
|||||||
else if (errorMessage.contains("session has expired"))
|
else if (errorMessage.contains("session has expired"))
|
||||||
new SessionExpiredException
|
new SessionExpiredException
|
||||||
else
|
else
|
||||||
new GenericException(ler.code, ler.statusLine, message)
|
new GenericException(code, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def extractLuxmedError(httpResponse: Try[HttpResponse[String]]) = {
|
private def extractLuxmedError(httpResponse: HttpResponse[String]) = {
|
||||||
httpResponse.flatMap { response =>
|
val body = httpResponse.body
|
||||||
Try(response.asEntity[LuxmedErrorsMap])
|
val code = httpResponse.code
|
||||||
.orElse(Try(response.asEntity[LuxmedErrorsList]))
|
Try(body.as[LuxmedErrorsMap])
|
||||||
.orElse(Try(response.asEntity[LuxmedError]))
|
.orElse(Try(body.as[LuxmedErrorsList]))
|
||||||
.map(e => luxmedErrorToApiException(e.asInstanceOf[HttpResponse[LuxmedBaseError]]))
|
.orElse(Try(body.as[LuxmedError]))
|
||||||
}.toOption
|
.map(error => luxmedErrorToApiException(code, error))
|
||||||
|
.toOption
|
||||||
}
|
}
|
||||||
|
|
||||||
private def hidePasswords(httpRequest: HttpRequest) = {
|
private def hidePasswords(httpRequest: HttpRequest) = {
|
||||||
|
|||||||
@@ -2,5 +2,5 @@
|
|||||||
package com.lbs.api.json.model
|
package com.lbs.api.json.model
|
||||||
|
|
||||||
case class LuxmedErrorsMap(errors: Map[String, List[String]]) extends SerializableJsonObject with LuxmedBaseError {
|
case class LuxmedErrorsMap(errors: Map[String, List[String]]) extends SerializableJsonObject with LuxmedBaseError {
|
||||||
override def message: String = errors.values.mkString("; ")
|
override def message: String = errors.values.map(_.mkString("; ")).mkString("; ")
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,18 @@
|
|||||||
|
|
||||||
package com.lbs
|
package com.lbs
|
||||||
|
|
||||||
|
import cats.MonadError
|
||||||
|
import cats.implicits._
|
||||||
import com.lbs.api.json.model.{AvailableTermsResponse, ReservationFilterResponse, ReservedVisitsResponse, VisitsHistoryResponse}
|
import com.lbs.api.json.model.{AvailableTermsResponse, ReservationFilterResponse, ReservedVisitsResponse, VisitsHistoryResponse}
|
||||||
import com.softwaremill.quicklens._
|
import com.softwaremill.quicklens._
|
||||||
|
|
||||||
|
import scala.language.higherKinds
|
||||||
import scala.util.matching.Regex
|
import scala.util.matching.Regex
|
||||||
|
|
||||||
package object api {
|
package object api {
|
||||||
|
|
||||||
|
type ThrowableMonad[F[_]] = MonadError[F, Throwable]
|
||||||
|
|
||||||
object ApiResponseMutators {
|
object ApiResponseMutators {
|
||||||
private val DoctorPrefixes: Regex = """\s*(dr\s*n.\s*med.|dr\s*hab.\s*n.\s*med|lek.\s*med.|lek.\s*stom.)\s*""".r
|
private val DoctorPrefixes: Regex = """\s*(dr\s*n.\s*med.|dr\s*hab.\s*n.\s*med|lek.\s*med.|lek.\s*stom.)\s*""".r
|
||||||
|
|
||||||
@@ -17,8 +22,8 @@ package object api {
|
|||||||
def mutate(response: T): T
|
def mutate(response: T): T
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class ResponseOps[T: ResponseMutator](response: Either[Throwable, T]) {
|
implicit class ResponseOps[T: ResponseMutator, F[_] : ThrowableMonad](response: F[T]) {
|
||||||
def mutate: Either[Throwable, T] = {
|
def mutate: F[T] = {
|
||||||
val mutator = implicitly[ResponseMutator[T]]
|
val mutator = implicitly[ResponseMutator[T]]
|
||||||
response.map(mutator.mutate)
|
response.map(mutator.mutate)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.lbs.api.http
|
||||||
|
|
||||||
|
import cats.instances.either._
|
||||||
|
import com.lbs.api.exception.GenericException
|
||||||
|
import org.mockito.Mockito._
|
||||||
|
import org.scalatest.mockito.MockitoSugar
|
||||||
|
import org.scalatest.{BeforeAndAfterEach, FunSuiteLike, Matchers}
|
||||||
|
import scalaj.http.{HttpRequest, HttpResponse}
|
||||||
|
|
||||||
|
class ExtendedHttpRequestSpec extends FunSuiteLike with Matchers with MockitoSugar with BeforeAndAfterEach {
|
||||||
|
|
||||||
|
private val request = mock[HttpRequest]
|
||||||
|
private type ThrowableOr[T] = Either[Throwable, T]
|
||||||
|
|
||||||
|
override protected def beforeEach(): Unit = {
|
||||||
|
reset(request)
|
||||||
|
when(request.params).thenReturn(Seq())
|
||||||
|
}
|
||||||
|
|
||||||
|
test("ok response") {
|
||||||
|
val okResponse = HttpResponse("ok", 200, Map())
|
||||||
|
when(request.asString).thenReturn(okResponse)
|
||||||
|
|
||||||
|
assert(invoke(request) == Right(okResponse))
|
||||||
|
}
|
||||||
|
|
||||||
|
test("error response") {
|
||||||
|
val errorResponse = HttpResponse("""{"Errors":{"ToDate.Date":["'To Date. Date' must be greater than or equal to '06/04/2018 00:00:00'."]}}""", 200, Map())
|
||||||
|
when(request.asString).thenReturn(errorResponse)
|
||||||
|
val result = invoke(request)
|
||||||
|
|
||||||
|
assert(result == Left(GenericException(200, "'To Date. Date' must be greater than or equal to '06/04/2018 00:00:00'.")))
|
||||||
|
}
|
||||||
|
|
||||||
|
private def invoke(request: HttpRequest) = {
|
||||||
|
ExtendedHttpRequest[ThrowableOr](request).invoke
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,4 +2,5 @@ dependencies {
|
|||||||
compile group: "org.slf4j", name: "slf4j-api", version: "1.7.25"
|
compile group: "org.slf4j", name: "slf4j-api", version: "1.7.25"
|
||||||
compile group: "ch.qos.logback", name: "logback-classic", version: "1.2.3"
|
compile group: "ch.qos.logback", name: "logback-classic", version: "1.2.3"
|
||||||
compile group: "ch.qos.logback", name: "logback-core", version: "1.2.3"
|
compile group: "ch.qos.logback", name: "logback-core", version: "1.2.3"
|
||||||
|
compile("org.typelevel:cats-core_2.12:2.0.0-M1")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import akka.actor.ActorSystem
|
|||||||
import com.lbs.api.json.model.IdName
|
import com.lbs.api.json.model.IdName
|
||||||
import com.lbs.bot.model.{Button, Command, TaggedButton}
|
import com.lbs.bot.model.{Button, Command, TaggedButton}
|
||||||
import com.lbs.bot.{Bot, _}
|
import com.lbs.bot.{Bot, _}
|
||||||
|
import com.lbs.server.ThrowableOr
|
||||||
import com.lbs.server.conversation.Login.UserId
|
import com.lbs.server.conversation.Login.UserId
|
||||||
import com.lbs.server.conversation.StaticData._
|
import com.lbs.server.conversation.StaticData._
|
||||||
import com.lbs.server.conversation.base.{Conversation, Interactional}
|
import com.lbs.server.conversation.base.{Conversation, Interactional}
|
||||||
@@ -78,6 +79,6 @@ object StaticData {
|
|||||||
|
|
||||||
case class FindOptions(searchText: String)
|
case class FindOptions(searchText: String)
|
||||||
|
|
||||||
case class FoundOptions(option: Either[Throwable, List[IdName]])
|
case class FoundOptions(option: ThrowableOr[List[IdName]])
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -6,12 +6,13 @@ import com.lbs.bot.model.Command
|
|||||||
import com.lbs.server.conversation.Book.BookingData
|
import com.lbs.server.conversation.Book.BookingData
|
||||||
import com.lbs.server.conversation.StaticData.{FindOptions, FoundOptions, LatestOptions, StaticDataConfig}
|
import com.lbs.server.conversation.StaticData.{FindOptions, FoundOptions, LatestOptions, StaticDataConfig}
|
||||||
import com.lbs.server.conversation.base.Conversation
|
import com.lbs.server.conversation.base.Conversation
|
||||||
|
import com.lbs.server.ThrowableOr
|
||||||
|
|
||||||
trait StaticDataForBooking extends Conversation[BookingData] {
|
trait StaticDataForBooking extends Conversation[BookingData] {
|
||||||
|
|
||||||
private[conversation] def staticData: StaticData
|
private[conversation] def staticData: StaticData
|
||||||
|
|
||||||
protected def withFunctions(latestOptions: => Seq[IdName], staticOptions: => Either[Throwable, List[IdName]], applyId: IdName => BookingData): Step => MessageProcessorFn = {
|
protected def withFunctions(latestOptions: => Seq[IdName], staticOptions: => ThrowableOr[List[IdName]], applyId: IdName => BookingData): Step => MessageProcessorFn = {
|
||||||
nextStep: Step => {
|
nextStep: Step => {
|
||||||
case Msg(cmd: Command, _) =>
|
case Msg(cmd: Command, _) =>
|
||||||
staticData ! cmd
|
staticData ! cmd
|
||||||
@@ -38,7 +39,7 @@ trait StaticDataForBooking extends Conversation[BookingData] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def filterOptions(options: Either[Throwable, List[IdName]], searchText: String) = {
|
private def filterOptions(options: ThrowableOr[List[IdName]], searchText: String) = {
|
||||||
options.map(opt => opt.filter(c => c.name.toLowerCase.contains(searchText)))
|
options.map(opt => opt.filter(c => c.name.toLowerCase.contains(searchText)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
5
server/src/main/scala/com/lbs/server/package.scala
Normal file
5
server/src/main/scala/com/lbs/server/package.scala
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package com.lbs
|
||||||
|
|
||||||
|
package object server {
|
||||||
|
type ThrowableOr[T] = Either[Throwable, T]
|
||||||
|
}
|
||||||
@@ -3,8 +3,10 @@ package com.lbs.server.service
|
|||||||
|
|
||||||
import java.time.{LocalTime, ZonedDateTime}
|
import java.time.{LocalTime, ZonedDateTime}
|
||||||
|
|
||||||
|
import cats.instances.either._
|
||||||
import com.lbs.api.LuxmedApi
|
import com.lbs.api.LuxmedApi
|
||||||
import com.lbs.api.json.model._
|
import com.lbs.api.json.model._
|
||||||
|
import com.lbs.server.ThrowableOr
|
||||||
import com.lbs.server.util.ServerModelConverters._
|
import com.lbs.server.util.ServerModelConverters._
|
||||||
import org.jasypt.util.text.TextEncryptor
|
import org.jasypt.util.text.TextEncryptor
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
@@ -19,34 +21,36 @@ class ApiService extends SessionSupport {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private var textEncryptor: TextEncryptor = _
|
private var textEncryptor: TextEncryptor = _
|
||||||
|
|
||||||
def getAllCities(accountId: Long): Either[Throwable, List[IdName]] =
|
private val luxmedApi = new LuxmedApi[ThrowableOr]
|
||||||
|
|
||||||
|
def getAllCities(accountId: Long): ThrowableOr[List[IdName]] =
|
||||||
withSession(accountId) { session =>
|
withSession(accountId) { session =>
|
||||||
LuxmedApi.reservationFilter(session.accessToken, session.tokenType).map(_.cities)
|
luxmedApi.reservationFilter(session.accessToken, session.tokenType).map(_.cities)
|
||||||
}
|
}
|
||||||
|
|
||||||
def getAllClinics(accountId: Long, cityId: Long): Either[Throwable, List[IdName]] =
|
def getAllClinics(accountId: Long, cityId: Long): ThrowableOr[List[IdName]] =
|
||||||
withSession(accountId) { session =>
|
withSession(accountId) { session =>
|
||||||
LuxmedApi.reservationFilter(session.accessToken,
|
luxmedApi.reservationFilter(session.accessToken,
|
||||||
session.tokenType, cityId = Some(cityId)).map(_.clinics)
|
session.tokenType, cityId = Some(cityId)).map(_.clinics)
|
||||||
}
|
}
|
||||||
|
|
||||||
def getAllServices(accountId: Long, cityId: Long, clinicId: Option[Long]): Either[Throwable, List[IdName]] =
|
def getAllServices(accountId: Long, cityId: Long, clinicId: Option[Long]): ThrowableOr[List[IdName]] =
|
||||||
withSession(accountId) { session =>
|
withSession(accountId) { session =>
|
||||||
LuxmedApi.reservationFilter(session.accessToken,
|
luxmedApi.reservationFilter(session.accessToken,
|
||||||
session.tokenType, cityId = Some(cityId),
|
session.tokenType, cityId = Some(cityId),
|
||||||
clinicId = clinicId).map(_.services)
|
clinicId = clinicId).map(_.services)
|
||||||
}
|
}
|
||||||
|
|
||||||
def getAllDoctors(accountId: Long, cityId: Long, clinicId: Option[Long], serviceId: Long): Either[Throwable, List[IdName]] =
|
def getAllDoctors(accountId: Long, cityId: Long, clinicId: Option[Long], serviceId: Long): ThrowableOr[List[IdName]] =
|
||||||
withSession(accountId) { session =>
|
withSession(accountId) { session =>
|
||||||
LuxmedApi.reservationFilter(session.accessToken,
|
luxmedApi.reservationFilter(session.accessToken,
|
||||||
session.tokenType, cityId = Some(cityId),
|
session.tokenType, cityId = Some(cityId),
|
||||||
clinicId = clinicId, serviceId = Some(serviceId)).map(_.doctors)
|
clinicId = clinicId, serviceId = Some(serviceId)).map(_.doctors)
|
||||||
}
|
}
|
||||||
|
|
||||||
def getPayers(accountId: Long, cityId: Long, clinicId: Option[Long], serviceId: Long): Either[Throwable, (Option[IdName], Seq[IdName])] =
|
def getPayers(accountId: Long, cityId: Long, clinicId: Option[Long], serviceId: Long): ThrowableOr[(Option[IdName], Seq[IdName])] =
|
||||||
withSession(accountId) { session =>
|
withSession(accountId) { session =>
|
||||||
val reservationFilterResponse = LuxmedApi.reservationFilter(session.accessToken,
|
val reservationFilterResponse = luxmedApi.reservationFilter(session.accessToken,
|
||||||
session.tokenType, cityId = Some(cityId),
|
session.tokenType, cityId = Some(cityId),
|
||||||
clinicId = clinicId, serviceId = Some(serviceId))
|
clinicId = clinicId, serviceId = Some(serviceId))
|
||||||
reservationFilterResponse.map { response =>
|
reservationFilterResponse.map { response =>
|
||||||
@@ -56,9 +60,9 @@ class ApiService extends SessionSupport {
|
|||||||
|
|
||||||
def getAvailableTerms(accountId: Long, payerId: Long, cityId: Long, clinicId: Option[Long], serviceId: Long, doctorId: Option[Long],
|
def getAvailableTerms(accountId: Long, payerId: Long, cityId: Long, clinicId: Option[Long], serviceId: Long, doctorId: Option[Long],
|
||||||
fromDate: ZonedDateTime = ZonedDateTime.now(), toDate: Option[ZonedDateTime] = None, timeFrom: LocalTime, timeTo: LocalTime,
|
fromDate: ZonedDateTime = ZonedDateTime.now(), toDate: Option[ZonedDateTime] = None, timeFrom: LocalTime, timeTo: LocalTime,
|
||||||
languageId: Long = 10, findFirstFreeTerm: Boolean = false): Either[Throwable, List[AvailableVisitsTermPresentation]] =
|
languageId: Long = 10, findFirstFreeTerm: Boolean = false): ThrowableOr[List[AvailableVisitsTermPresentation]] =
|
||||||
withSession(accountId) { session =>
|
withSession(accountId) { session =>
|
||||||
val termsEither = LuxmedApi.availableTerms(session.accessToken, session.tokenType, payerId, cityId, clinicId, serviceId, doctorId,
|
val termsEither = luxmedApi.availableTerms(session.accessToken, session.tokenType, payerId, cityId, clinicId, serviceId, doctorId,
|
||||||
fromDate, toDate, languageId = languageId, findFirstFreeTerm = findFirstFreeTerm).map(_.availableVisitsTermPresentation)
|
fromDate, toDate, languageId = languageId, findFirstFreeTerm = findFirstFreeTerm).map(_.availableVisitsTermPresentation)
|
||||||
termsEither.map { terms =>
|
termsEither.map { terms =>
|
||||||
terms.filter { term =>
|
terms.filter { term =>
|
||||||
@@ -68,25 +72,25 @@ class ApiService extends SessionSupport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def temporaryReservation(accountId: Long, temporaryReservationRequest: TemporaryReservationRequest, valuationsRequest: ValuationsRequest): Either[Throwable, (TemporaryReservationResponse, ValuationsResponse)] =
|
def temporaryReservation(accountId: Long, temporaryReservationRequest: TemporaryReservationRequest, valuationsRequest: ValuationsRequest): ThrowableOr[(TemporaryReservationResponse, ValuationsResponse)] =
|
||||||
withSession(accountId) { session =>
|
withSession(accountId) { session =>
|
||||||
for {
|
for {
|
||||||
temporaryReservation <- LuxmedApi.temporaryReservation(session.accessToken, session.tokenType, temporaryReservationRequest)
|
temporaryReservation <- luxmedApi.temporaryReservation(session.accessToken, session.tokenType, temporaryReservationRequest)
|
||||||
valuationsResponse <- LuxmedApi.valuations(session.accessToken, session.tokenType, valuationsRequest)
|
valuationsResponse <- luxmedApi.valuations(session.accessToken, session.tokenType, valuationsRequest)
|
||||||
} yield temporaryReservation -> valuationsResponse
|
} yield temporaryReservation -> valuationsResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
def deleteTemporaryReservation(accountId: Long, temporaryReservationId: Long): Either[Throwable, HttpResponse[String]] =
|
def deleteTemporaryReservation(accountId: Long, temporaryReservationId: Long): ThrowableOr[HttpResponse[String]] =
|
||||||
withSession(accountId) { session =>
|
withSession(accountId) { session =>
|
||||||
LuxmedApi.deleteTemporaryReservation(session.accessToken, session.tokenType, temporaryReservationId)
|
luxmedApi.deleteTemporaryReservation(session.accessToken, session.tokenType, temporaryReservationId)
|
||||||
}
|
}
|
||||||
|
|
||||||
def reservation(accountId: Long, reservationRequest: ReservationRequest): Either[Throwable, ReservationResponse] =
|
def reservation(accountId: Long, reservationRequest: ReservationRequest): ThrowableOr[ReservationResponse] =
|
||||||
withSession(accountId) { session =>
|
withSession(accountId) { session =>
|
||||||
LuxmedApi.reservation(session.accessToken, session.tokenType, reservationRequest)
|
luxmedApi.reservation(session.accessToken, session.tokenType, reservationRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
def reserveVisit(accountId: Long, term: AvailableVisitsTermPresentation): Either[Throwable, ReservationResponse] = {
|
def reserveVisit(accountId: Long, term: AvailableVisitsTermPresentation): ThrowableOr[ReservationResponse] = {
|
||||||
val temporaryReservationRequest = term.mapTo[TemporaryReservationRequest]
|
val temporaryReservationRequest = term.mapTo[TemporaryReservationRequest]
|
||||||
val valuationsRequest = term.mapTo[ValuationsRequest]
|
val valuationsRequest = term.mapTo[ValuationsRequest]
|
||||||
for {
|
for {
|
||||||
@@ -99,38 +103,38 @@ class ApiService extends SessionSupport {
|
|||||||
} yield reservation
|
} yield reservation
|
||||||
}
|
}
|
||||||
|
|
||||||
def canTermBeChanged(accountId: Long, reservationId: Long): Either[Throwable, HttpResponse[String]] =
|
def canTermBeChanged(accountId: Long, reservationId: Long): ThrowableOr[HttpResponse[String]] =
|
||||||
withSession(accountId) { session =>
|
withSession(accountId) { session =>
|
||||||
LuxmedApi.canTermBeChanged(session.accessToken, session.tokenType, reservationId)
|
luxmedApi.canTermBeChanged(session.accessToken, session.tokenType, reservationId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def detailToChangeTerm(accountId: Long, reservationId: Long): Either[Throwable, ChangeTermDetailsResponse] =
|
def detailToChangeTerm(accountId: Long, reservationId: Long): ThrowableOr[ChangeTermDetailsResponse] =
|
||||||
withSession(accountId) { session =>
|
withSession(accountId) { session =>
|
||||||
LuxmedApi.detailToChangeTerm(session.accessToken, session.tokenType, reservationId)
|
luxmedApi.detailToChangeTerm(session.accessToken, session.tokenType, reservationId)
|
||||||
}
|
}
|
||||||
|
|
||||||
def temporaryReservationToChangeTerm(accountId: Long, reservationId: Long, temporaryReservationRequest: TemporaryReservationRequest, valuationsRequest: ValuationsRequest): Either[Throwable, (TemporaryReservationResponse, ValuationsResponse)] =
|
def temporaryReservationToChangeTerm(accountId: Long, reservationId: Long, temporaryReservationRequest: TemporaryReservationRequest, valuationsRequest: ValuationsRequest): ThrowableOr[(TemporaryReservationResponse, ValuationsResponse)] =
|
||||||
withSession(accountId) { session =>
|
withSession(accountId) { session =>
|
||||||
for {
|
for {
|
||||||
temporaryReservation <- LuxmedApi.temporaryReservationToChangeTerm(session.accessToken, session.tokenType, reservationId, temporaryReservationRequest)
|
temporaryReservation <- luxmedApi.temporaryReservationToChangeTerm(session.accessToken, session.tokenType, reservationId, temporaryReservationRequest)
|
||||||
valuationsResponse <- LuxmedApi.valuationToChangeTerm(session.accessToken, session.tokenType, reservationId, valuationsRequest)
|
valuationsResponse <- luxmedApi.valuationToChangeTerm(session.accessToken, session.tokenType, reservationId, valuationsRequest)
|
||||||
} yield temporaryReservation -> valuationsResponse
|
} yield temporaryReservation -> valuationsResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
def valuationToChangeTerm(accountId: Long, reservationId: Long, valuationsRequest: ValuationsRequest): Either[Throwable, ValuationsResponse] =
|
def valuationToChangeTerm(accountId: Long, reservationId: Long, valuationsRequest: ValuationsRequest): ThrowableOr[ValuationsResponse] =
|
||||||
withSession(accountId) { session =>
|
withSession(accountId) { session =>
|
||||||
LuxmedApi.valuationToChangeTerm(session.accessToken, session.tokenType, reservationId, valuationsRequest)
|
luxmedApi.valuationToChangeTerm(session.accessToken, session.tokenType, reservationId, valuationsRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
def changeTerm(accountId: Long, reservationId: Long, reservationRequest: ReservationRequest): Either[Throwable, ChangeTermResponse] =
|
def changeTerm(accountId: Long, reservationId: Long, reservationRequest: ReservationRequest): ThrowableOr[ChangeTermResponse] =
|
||||||
withSession(accountId) { session =>
|
withSession(accountId) { session =>
|
||||||
LuxmedApi.changeTerm(session.accessToken, session.tokenType, reservationId, reservationRequest)
|
luxmedApi.changeTerm(session.accessToken, session.tokenType, reservationId, reservationRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
def updateReservedVisit(accountId: Long, term: AvailableVisitsTermPresentation): Either[Throwable, ChangeTermResponse] = {
|
def updateReservedVisit(accountId: Long, term: AvailableVisitsTermPresentation): ThrowableOr[ChangeTermResponse] = {
|
||||||
val reservedVisitEither = reservedVisits(accountId, toDate = ZonedDateTime.now().plusMonths(6)).map(_.find(_.service.id == term.serviceId))
|
val reservedVisitMaybe = reservedVisits(accountId, toDate = ZonedDateTime.now().plusMonths(6)).map(_.find(_.service.id == term.serviceId))
|
||||||
reservedVisitEither match {
|
reservedVisitMaybe match {
|
||||||
case Right(Some(reservedVisit: ReservedVisit)) =>
|
case Right(Some(reservedVisit: ReservedVisit)) =>
|
||||||
val reservationId = reservedVisit.reservationId
|
val reservationId = reservedVisit.reservationId
|
||||||
val temporaryReservationRequest = term.mapTo[TemporaryReservationRequest]
|
val temporaryReservationRequest = term.mapTo[TemporaryReservationRequest]
|
||||||
@@ -154,24 +158,24 @@ class ApiService extends SessionSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def visitsHistory(accountId: Long, fromDate: ZonedDateTime = ZonedDateTime.now().minusYears(1),
|
def visitsHistory(accountId: Long, fromDate: ZonedDateTime = ZonedDateTime.now().minusYears(1),
|
||||||
toDate: ZonedDateTime = ZonedDateTime.now(), page: Int = 1, pageSize: Int = 100): Either[Throwable, List[HistoricVisit]] =
|
toDate: ZonedDateTime = ZonedDateTime.now(), page: Int = 1, pageSize: Int = 100): ThrowableOr[List[HistoricVisit]] =
|
||||||
withSession(accountId) { session =>
|
withSession(accountId) { session =>
|
||||||
LuxmedApi.visitsHistory(session.accessToken, session.tokenType, fromDate, toDate, page, pageSize).map(_.historicVisits)
|
luxmedApi.visitsHistory(session.accessToken, session.tokenType, fromDate, toDate, page, pageSize).map(_.historicVisits)
|
||||||
}
|
}
|
||||||
|
|
||||||
def reservedVisits(accountId: Long, fromDate: ZonedDateTime = ZonedDateTime.now(),
|
def reservedVisits(accountId: Long, fromDate: ZonedDateTime = ZonedDateTime.now(),
|
||||||
toDate: ZonedDateTime = ZonedDateTime.now().plusMonths(3)): Either[Throwable, List[ReservedVisit]] =
|
toDate: ZonedDateTime = ZonedDateTime.now().plusMonths(3)): ThrowableOr[List[ReservedVisit]] =
|
||||||
withSession(accountId) { session =>
|
withSession(accountId) { session =>
|
||||||
LuxmedApi.reservedVisits(session.accessToken, session.tokenType, fromDate, toDate).map(_.reservedVisits)
|
luxmedApi.reservedVisits(session.accessToken, session.tokenType, fromDate, toDate).map(_.reservedVisits)
|
||||||
}
|
}
|
||||||
|
|
||||||
def deleteReservation(accountId: Long, reservationId: Long): Either[Throwable, HttpResponse[String]] =
|
def deleteReservation(accountId: Long, reservationId: Long): ThrowableOr[HttpResponse[String]] =
|
||||||
withSession(accountId) { session =>
|
withSession(accountId) { session =>
|
||||||
LuxmedApi.deleteReservation(session.accessToken, session.tokenType, reservationId)
|
luxmedApi.deleteReservation(session.accessToken, session.tokenType, reservationId)
|
||||||
}
|
}
|
||||||
|
|
||||||
def login(username: String, password: String): Either[Throwable, LoginResponse] = {
|
def login(username: String, password: String): ThrowableOr[LoginResponse] = {
|
||||||
LuxmedApi.login(username, textEncryptor.decrypt(password))
|
luxmedApi.login(username, textEncryptor.decrypt(password))
|
||||||
}
|
}
|
||||||
|
|
||||||
private def left(msg: String) = Left(new RuntimeException(msg))
|
private def left(msg: String) = Left(new RuntimeException(msg))
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package com.lbs.server.service
|
|||||||
import com.lbs.api.exception.SessionExpiredException
|
import com.lbs.api.exception.SessionExpiredException
|
||||||
import com.lbs.api.json.model.LoginResponse
|
import com.lbs.api.json.model.LoginResponse
|
||||||
import com.lbs.common.{Logger, ParametrizedLock}
|
import com.lbs.common.{Logger, ParametrizedLock}
|
||||||
|
import com.lbs.server.ThrowableOr
|
||||||
import com.lbs.server.exception.UserNotFoundException
|
import com.lbs.server.exception.UserNotFoundException
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
@@ -12,7 +13,7 @@ trait SessionSupport extends Logger {
|
|||||||
|
|
||||||
case class Session(accessToken: String, tokenType: String)
|
case class Session(accessToken: String, tokenType: String)
|
||||||
|
|
||||||
def login(username: String, password: String): Either[Throwable, LoginResponse]
|
def login(username: String, password: String): ThrowableOr[LoginResponse]
|
||||||
|
|
||||||
protected def dataService: DataService
|
protected def dataService: DataService
|
||||||
|
|
||||||
@@ -20,10 +21,10 @@ trait SessionSupport extends Logger {
|
|||||||
|
|
||||||
private val lock = new ParametrizedLock[Long]
|
private val lock = new ParametrizedLock[Long]
|
||||||
|
|
||||||
protected def withSession[T](accountId: Long)(fn: Session => Either[Throwable, T]): Either[Throwable, T] =
|
protected def withSession[T](accountId: Long)(fn: Session => ThrowableOr[T]): ThrowableOr[T] =
|
||||||
lock.obtainLock(accountId).synchronized {
|
lock.obtainLock(accountId).synchronized {
|
||||||
|
|
||||||
def auth: Either[Throwable, Session] = {
|
def auth: ThrowableOr[Session] = {
|
||||||
val credentialsMaybe = dataService.getCredentials(accountId)
|
val credentialsMaybe = dataService.getCredentials(accountId)
|
||||||
credentialsMaybe match {
|
credentialsMaybe match {
|
||||||
case Some(credentials) =>
|
case Some(credentials) =>
|
||||||
@@ -33,7 +34,7 @@ trait SessionSupport extends Logger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def getSession: Either[Throwable, Session] = {
|
def getSession: ThrowableOr[Session] = {
|
||||||
sessions.get(accountId) match {
|
sessions.get(accountId) match {
|
||||||
case Some(sess) => Right(sess)
|
case Some(sess) => Right(sess)
|
||||||
case None =>
|
case None =>
|
||||||
|
|||||||
Reference in New Issue
Block a user