diff --git a/server/src/main/scala/com/lbs/server/BootConfig.scala b/server/src/main/scala/com/lbs/server/BootConfig.scala
index 6ee1c65..71edf75 100644
--- a/server/src/main/scala/com/lbs/server/BootConfig.scala
+++ b/server/src/main/scala/com/lbs/server/BootConfig.scala
@@ -102,10 +102,14 @@ class BootConfig {
def settingsActorFactory: ByUserIdActorFactory =
userId => actorSystem.actorOf(Settings.props(userId, bot, dataService, localization))
+ @Bean
+ def accountActorFactory: ByUserIdActorFactory =
+ userId => actorSystem.actorOf(Account.props(userId, bot, dataService, localization, router))
+
@Bean
def chatActorFactory: ByUserIdActorFactory =
userId => actorSystem.actorOf(Chat.props(userId, dataService, monitoringService, bookingActorFactory, helpActorFactory,
- monitoringsActorFactory, historyActorFactory, visitsActorFactory, settingsActorFactory, bugActorFactory))
+ monitoringsActorFactory, historyActorFactory, visitsActorFactory, settingsActorFactory, bugActorFactory, accountActorFactory))
@Bean
def datePickerFactory: ByUserIdWithOriginatorActorFactory = (userId, originator) =>
diff --git a/server/src/main/scala/com/lbs/server/actor/Account.scala b/server/src/main/scala/com/lbs/server/actor/Account.scala
new file mode 100644
index 0000000..9f9e312
--- /dev/null
+++ b/server/src/main/scala/com/lbs/server/actor/Account.scala
@@ -0,0 +1,103 @@
+/**
+ * MIT License
+ *
+ * Copyright (c) 2018 Yevhen Zadyra
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.lbs.server.actor
+
+import akka.actor.{ActorRef, Props}
+import com.lbs.bot.model.{Button, Command}
+import com.lbs.bot.{Bot, _}
+import com.lbs.server.actor.Account._
+import com.lbs.server.actor.Chat.Init
+import com.lbs.server.actor.Login._
+import com.lbs.server.lang.{Localizable, Localization}
+import com.lbs.server.service.DataService
+
+class Account(val userId: UserId, bot: Bot, dataService: DataService, val localization: Localization, router: ActorRef) extends SafeFSM[FSMState, FSMData] with Localizable {
+
+ startWith(AskAction, null)
+
+ whenSafe(AskAction) {
+ case Event(Next, _) =>
+ val credentials = dataService.getUserCredentials(userId.userId)
+ 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, inlineKeyboard = createInlineKeyboard(buttons, columns = 1))
+ goto(AwaitAction)
+ }
+
+ whenSafe(AwaitAction) {
+ case Event(cmd@Command(_, _, Some(actionStr)), _) =>
+ val action = actionStr.toLong
+ action match {
+ case -1L =>
+ router ! cmd.copy(message = cmd.message.copy(text = Some("/login")))
+ goto(AskAction) using null
+ case -2L =>
+ bot.sendMessage(userId.source, "Not implemented yet")
+ goto(AskAction) using null
+ case accountId =>
+ val accountMaybe = dataService.findUserCredentialsByAccountId(userId.userId, accountId)
+ accountMaybe match {
+ case Some(account) => //account was found
+ val userMaybe = dataService.findUser(userId.userId)
+ userMaybe.foreach { user =>
+ user.activeAccountId = accountId
+ dataService.saveUser(user)
+ router ! SwitchUser(UserId(account.userId, account.accountId, userId.source))
+ bot.sendMessage(userId.source, lang.accountSwitched(account.username))
+ }
+ goto(AskAction) using null
+ case None =>
+ LOG.error(s"This is not user [#${userId.userId}] account [#$accountId]")
+ goto(AskAction) using null
+ }
+ }
+ }
+
+ whenUnhandledSafe {
+ case Event(Init, _) =>
+ invokeNext()
+ goto(AskAction) using null
+ case e: Event =>
+ LOG.error(s"Unhandled event in state:$stateName. Event: $e")
+ stay()
+ }
+
+ initialize()
+
+}
+
+object Account {
+ def props(userId: UserId, bot: Bot, dataService: DataService, localization: Localization, router: ActorRef): Props =
+ Props(new Account(userId, bot, dataService, localization, router))
+
+ object AskAction extends FSMState
+
+ object AwaitAction extends FSMState
+
+ object AddAccount extends FSMState
+
+ object RemoveAccount extends FSMState
+
+ case class SwitchUser(userId: UserId)
+
+}
\ No newline at end of file
diff --git a/server/src/main/scala/com/lbs/server/actor/Auth.scala b/server/src/main/scala/com/lbs/server/actor/Auth.scala
index 03319f5..6d3dbce 100644
--- a/server/src/main/scala/com/lbs/server/actor/Auth.scala
+++ b/server/src/main/scala/com/lbs/server/actor/Auth.scala
@@ -54,22 +54,22 @@ class Auth(val source: MessageSource, dataService: DataService, unauthorizedHelp
case cmd: Command if userId.nonEmpty =>
chatActor = getChatActor(userId.get)
chatActor ! cmd
- case LoggedIn(forwardCommand, id) =>
- val uId = UserId(id, source)
+ case LoggedIn(forwardCommand, uId, aId) =>
+ val id = UserId(uId, aId, source)
val cmd = forwardCommand.cmd
- userId = Some(uId)
- chatActor = getChatActor(uId, reinit = true)
+ userId = Some(id)
+ chatActor = getChatActor(id, reInit = true)
if (!cmd.message.text.contains("/login"))
chatActor ! cmd
case cmd: Command =>
chatActor ! cmd
}
- private def getChatActor(userId: UserId, reinit: Boolean = false): ActorRef = {
+ private def getChatActor(userId: UserId, reInit: Boolean = false): ActorRef = {
if (chatActor == null) {
chatActorFactory(userId)
} else {
- if (reinit) {
+ if (reInit) {
chatActor ! PoisonPill
chatActorFactory(userId)
} else chatActor
@@ -77,8 +77,8 @@ class Auth(val source: MessageSource, dataService: DataService, unauthorizedHelp
}
def getUserId: Option[UserId] = {
- val userIdMaybe = dataService.findUserIdBySource(source)
- userIdMaybe.map(id => UserId(id, source))
+ val userIdMaybe = dataService.findUserAndAccountIdBySource(source)
+ userIdMaybe.map { case (uId, aId) => UserId(uId, aId, source) }
}
override def postStop(): Unit = {
diff --git a/server/src/main/scala/com/lbs/server/actor/Book.scala b/server/src/main/scala/com/lbs/server/actor/Book.scala
index 9f0c77b..b5877a9 100644
--- a/server/src/main/scala/com/lbs/server/actor/Book.scala
+++ b/server/src/main/scala/com/lbs/server/actor/Book.scala
@@ -53,29 +53,29 @@ class Book(val userId: UserId, bot: Bot, apiService: ApiService, dataService: Da
requestStaticData(RequestCity, AwaitCity, cityConfig) { bd: BookingData =>
withFunctions(
- latestOptions = dataService.getLatestCities(userId.userId),
- staticOptions = apiService.getAllCities(userId.userId),
+ latestOptions = dataService.getLatestCities(userId.accountId),
+ staticOptions = apiService.getAllCities(userId.accountId),
applyId = id => bd.copy(cityId = id))
}(requestNext = RequestClinic)
requestStaticData(RequestClinic, AwaitClinic, clinicConfig) { bd: BookingData =>
withFunctions(
- latestOptions = dataService.getLatestClinicsByCityId(userId.userId, bd.cityId.id),
- staticOptions = apiService.getAllClinics(userId.userId, bd.cityId.id),
+ latestOptions = dataService.getLatestClinicsByCityId(userId.accountId, bd.cityId.id),
+ staticOptions = apiService.getAllClinics(userId.accountId, bd.cityId.id),
applyId = id => bd.copy(clinicId = id))
}(requestNext = RequestService)
requestStaticData(RequestService, AwaitService, serviceConfig) { bd: BookingData =>
withFunctions(
- latestOptions = dataService.getLatestServicesByCityIdAndClinicId(userId.userId, bd.cityId.id, bd.clinicId.optionalId),
- staticOptions = apiService.getAllServices(userId.userId, bd.cityId.id, bd.clinicId.optionalId),
+ latestOptions = dataService.getLatestServicesByCityIdAndClinicId(userId.accountId, bd.cityId.id, bd.clinicId.optionalId),
+ staticOptions = apiService.getAllServices(userId.accountId, bd.cityId.id, bd.clinicId.optionalId),
applyId = id => bd.copy(serviceId = id))
}(requestNext = RequestDoctor)
requestStaticData(RequestDoctor, AwaitDoctor, doctorConfig) { bd: BookingData =>
withFunctions(
- latestOptions = dataService.getLatestDoctorsByCityIdAndClinicIdAndServiceId(userId.userId, bd.cityId.id, bd.clinicId.optionalId, bd.serviceId.id),
- staticOptions = apiService.getAllDoctors(userId.userId, bd.cityId.id, bd.clinicId.optionalId, bd.serviceId.id),
+ latestOptions = dataService.getLatestDoctorsByCityIdAndClinicIdAndServiceId(userId.accountId, bd.cityId.id, bd.clinicId.optionalId, bd.serviceId.id),
+ staticOptions = apiService.getAllDoctors(userId.accountId, bd.cityId.id, bd.clinicId.optionalId, bd.serviceId.id),
applyId = id => bd.copy(doctorId = id))
}(requestNext = RequestDateFrom)
@@ -128,7 +128,7 @@ class Book(val userId: UserId, bot: Bot, apiService: ApiService, dataService: Da
whenSafe(RequestAction) {
case Event(Next, bookingData: BookingData) =>
- dataService.storeAppointment(userId.userId, bookingData)
+ dataService.storeAppointment(userId.accountId, bookingData)
bot.sendMessage(userId.source,
lang.bookingSummary(bookingData),
inlineKeyboard = createInlineKeyboard(Seq(Button(lang.findTerms, Tags.FindTerms), Button(lang.modifyDate, Tags.ModifyDate))))
@@ -146,7 +146,7 @@ class Book(val userId: UserId, bot: Bot, apiService: ApiService, dataService: Da
whenSafe(RequestTerm) {
case Event(Next, bookingData: BookingData) =>
- val availableTerms = apiService.getAvailableTerms(userId.userId, bookingData.cityId.id,
+ val availableTerms = apiService.getAvailableTerms(userId.accountId, bookingData.cityId.id,
bookingData.clinicId.optionalId, bookingData.serviceId.id, bookingData.doctorId.optionalId,
bookingData.dateFrom, Some(bookingData.dateTo), timeOfDay = bookingData.timeOfDay)
termsPager ! availableTerms
@@ -174,7 +174,7 @@ class Book(val userId: UserId, bot: Bot, apiService: ApiService, dataService: Da
whenSafe(RequestReservation) {
case Event(term: AvailableVisitsTermPresentation, bookingData: BookingData) =>
- val response = apiService.temporaryReservation(userId.userId, term.mapTo[TemporaryReservationRequest], term.mapTo[ValuationsRequest])
+ val response = apiService.temporaryReservation(userId.accountId, term.mapTo[TemporaryReservationRequest], term.mapTo[ValuationsRequest])
response match {
case Left(ex) =>
bot.sendMessage(userId.source, ex.getMessage)
@@ -189,7 +189,7 @@ class Book(val userId: UserId, bot: Bot, apiService: ApiService, dataService: Da
whenSafe(AwaitReservation) {
case Event(Command(_, _, Some(Tags.Cancel)), bookingData: BookingData) =>
- apiService.deleteTemporaryReservation(userId.userId, bookingData.temporaryReservationId.get)
+ apiService.deleteTemporaryReservation(userId.accountId, bookingData.temporaryReservationId.get)
stay()
case Event(Command(_, _, Some(Tags.Book)), bookingData: BookingData) =>
val reservationRequestMaybe = for {
@@ -201,7 +201,7 @@ class Book(val userId: UserId, bot: Bot, apiService: ApiService, dataService: Da
reservationRequestMaybe match {
case Some(reservationRequest) =>
- apiService.reservation(userId.userId, reservationRequest) match {
+ apiService.reservation(userId.accountId, reservationRequest) match {
case Left(ex) =>
bot.sendMessage(userId.source, ex.getMessage)
invokeNext()
diff --git a/server/src/main/scala/com/lbs/server/actor/Chat.scala b/server/src/main/scala/com/lbs/server/actor/Chat.scala
index 6b70c73..a3bba33 100644
--- a/server/src/main/scala/com/lbs/server/actor/Chat.scala
+++ b/server/src/main/scala/com/lbs/server/actor/Chat.scala
@@ -36,7 +36,7 @@ import scala.util.matching.Regex
class Chat(val userId: UserId, dataService: DataService, monitoringService: MonitoringService, bookingActorFactory: ByUserIdActorFactory, helpActorFactory: ByUserIdActorFactory,
monitoringsActorFactory: ByUserIdActorFactory, historyActorFactory: ByUserIdActorFactory,
visitsActorFactory: ByUserIdActorFactory, settingsActorFactory: ByUserIdActorFactory,
- bugActorFactory: ByUserIdActorFactory) extends SafeFSM[FSMState, FSMData] with Logger {
+ bugActorFactory: ByUserIdActorFactory, accountActorFactory: ByUserIdActorFactory) extends SafeFSM[FSMState, FSMData] with Logger {
private val bookingActor = bookingActorFactory(userId)
private val helpActor = helpActorFactory(userId)
@@ -45,6 +45,7 @@ class Chat(val userId: UserId, dataService: DataService, monitoringService: Moni
private val visitsActor = visitsActorFactory(userId)
private val settingsActor = settingsActorFactory(userId)
private val bugActor = bugActorFactory(userId)
+ private val accountActor = accountActorFactory(userId)
startWith(HelpChat, null)
@@ -93,6 +94,12 @@ class Chat(val userId: UserId, dataService: DataService, monitoringService: Moni
stay()
}
+ when(AccountChat, accountActor) {
+ case Event(Command(_, Text("/accounts"), _), _) =>
+ accountActor ! Init
+ stay()
+ }
+
private def when(state: FSMState, actor: ActorRef)(mainStateFunction: StateFunction): Unit = {
whenSafe(state) {
case event: Event =>
@@ -130,11 +137,14 @@ class Chat(val userId: UserId, dataService: DataService, monitoringService: Moni
case Event(cmd@Command(_, Text("/settings"), _), _) =>
self ! cmd
goto(SettingsChat)
+ case Event(cmd@Command(_, Text("/accounts"), _), _) =>
+ self ! cmd
+ goto(AccountChat)
case Event(cmd@Command(_, Text(MonitoringId(monitoringIdStr, scheduleIdStr, timeStr)), _), _) =>
val monitoringId = monitoringIdStr.toLong
val scheduleId = scheduleIdStr.toLong
val time = timeStr.toLong
- monitoringService.bookAppointmentByScheduleId(userId.userId, monitoringId, scheduleId, time)
+ monitoringService.bookAppointmentByScheduleId(userId.accountId, monitoringId, scheduleId, time)
stay()
case Event(cmd: Command, _) =>
actor ! cmd
@@ -157,6 +167,7 @@ class Chat(val userId: UserId, dataService: DataService, monitoringService: Moni
visitsActor ! PoisonPill
settingsActor ! PoisonPill
bugActor ! PoisonPill
+ accountActor ! PoisonPill
super.postStop()
}
}
@@ -164,9 +175,10 @@ class Chat(val userId: UserId, dataService: DataService, monitoringService: Moni
object Chat {
def props(userId: UserId, dataService: DataService, monitoringService: MonitoringService, bookingActorFactory: ByUserIdActorFactory, helpActorFactory: ByUserIdActorFactory,
monitoringsActorFactory: ByUserIdActorFactory, historyActorFactory: ByUserIdActorFactory,
- visitsActorFactory: ByUserIdActorFactory, settingsActorFactory: ByUserIdActorFactory, bugActorFactory: ByUserIdActorFactory): Props =
+ visitsActorFactory: ByUserIdActorFactory, settingsActorFactory: ByUserIdActorFactory, bugActorFactory: ByUserIdActorFactory,
+ accountActorFactory: ByUserIdActorFactory): Props =
Props(new Chat(userId, dataService, monitoringService, bookingActorFactory, helpActorFactory, monitoringsActorFactory,
- historyActorFactory, visitsActorFactory, settingsActorFactory, bugActorFactory))
+ historyActorFactory, visitsActorFactory, settingsActorFactory, bugActorFactory, accountActorFactory))
object HelpChat extends FSMState
@@ -182,6 +194,8 @@ object Chat {
object BugChat extends FSMState
+ object AccountChat extends FSMState
+
object Init
val MonitoringId: Regex = s"/reserve_(\\d+)_(\\d+)_(\\d+)".r
diff --git a/server/src/main/scala/com/lbs/server/actor/History.scala b/server/src/main/scala/com/lbs/server/actor/History.scala
index 2748939..5b4e1c3 100644
--- a/server/src/main/scala/com/lbs/server/actor/History.scala
+++ b/server/src/main/scala/com/lbs/server/actor/History.scala
@@ -41,7 +41,7 @@ class History(val userId: UserId, bot: Bot, apiService: ApiService, val localiza
whenSafe(RequestData) {
case Event(Next, _) =>
- val visits = apiService.visitsHistory(userId.userId)
+ val visits = apiService.visitsHistory(userId.accountId)
historyPager ! visits
goto(AwaitPage)
}
diff --git a/server/src/main/scala/com/lbs/server/actor/Login.scala b/server/src/main/scala/com/lbs/server/actor/Login.scala
index 9d63735..e0c80d9 100644
--- a/server/src/main/scala/com/lbs/server/actor/Login.scala
+++ b/server/src/main/scala/com/lbs/server/actor/Login.scala
@@ -26,7 +26,6 @@ package com.lbs.server.actor
import akka.actor.{ActorRef, Props}
import com.lbs.bot.Bot
import com.lbs.bot.model.{Command, MessageSource}
-import com.lbs.bot.telegram.TelegramBot
import com.lbs.server.actor.Chat.Init
import com.lbs.server.actor.Login._
import com.lbs.server.lang.{Localizable, Localization}
@@ -56,10 +55,10 @@ class Login(source: MessageSource, bot: Bot, dataService: DataService, apiServic
goto(RequestUsername) using LoginData()
case Right(loggedIn) =>
val credentials = dataService.saveCredentials(source, username, password)
- userId = UserId(credentials.userId, source)
- apiService.addSession(credentials.userId, loggedIn.accessToken, loggedIn.tokenType)
+ userId = UserId(credentials.userId, credentials.accountId, source)
+ apiService.addSession(credentials.accountId, loggedIn.accessToken, loggedIn.tokenType)
bot.sendMessage(source, lang.loginAndPasswordAreOk)
- originator ! LoggedIn(forwardCommand, credentials.userId)
+ originator ! LoggedIn(forwardCommand, credentials.userId, credentials.accountId)
stay() using null
}
}
@@ -119,8 +118,8 @@ object Login {
case class ForwardCommand(cmd: Command)
- case class UserId(userId: Long, source: MessageSource)
+ case class UserId(userId: Long, accountId: Long, source: MessageSource)
- case class LoggedIn(forwardCommand: ForwardCommand, userId: Long)
+ case class LoggedIn(forwardCommand: ForwardCommand, userId: Long, accountId: Long)
}
\ No newline at end of file
diff --git a/server/src/main/scala/com/lbs/server/actor/Monitorings.scala b/server/src/main/scala/com/lbs/server/actor/Monitorings.scala
index 9eb80dc..34bc8d4 100644
--- a/server/src/main/scala/com/lbs/server/actor/Monitorings.scala
+++ b/server/src/main/scala/com/lbs/server/actor/Monitorings.scala
@@ -41,7 +41,7 @@ class Monitorings(val userId: UserId, bot: Bot, monitoringService: MonitoringSer
whenSafe(RequestData) {
case Event(Next, _) =>
- val monitorings = monitoringService.getActiveMonitorings(userId.userId)
+ val monitorings = monitoringService.getActiveMonitorings(userId.accountId)
monitoringsPager ! Right[Throwable, Seq[Monitoring]](monitorings)
goto(AwaitPage)
}
diff --git a/server/src/main/scala/com/lbs/server/actor/Router.scala b/server/src/main/scala/com/lbs/server/actor/Router.scala
index 63602b3..813d46a 100644
--- a/server/src/main/scala/com/lbs/server/actor/Router.scala
+++ b/server/src/main/scala/com/lbs/server/actor/Router.scala
@@ -26,6 +26,7 @@ package com.lbs.server.actor
import akka.actor.{Actor, ActorRef, Cancellable, PoisonPill, Props}
import com.lbs.bot.model.{Command, MessageSource}
import com.lbs.common.Logger
+import com.lbs.server.actor.Account.SwitchUser
import com.lbs.server.actor.Router.DestroyChat
import scala.collection.mutable
@@ -47,20 +48,34 @@ class Router(authActorFactory: ByMessageSourceActorFactory) extends Actor with L
scheduleIdleChatDestroyer(source)
val chat = chats.get(source) match {
case Some(actor) => actor
- case None =>
- val actor = authActorFactory(source)
- chats += source -> actor
- actor
+ case None => addNewChatActor(source)
}
chat ! cmd
case DestroyChat(source) =>
destroyChat(source)
+ case SwitchUser(userId) =>
+ switchUser(userId)
case what => LOG.info(s"Unknown message: $what")
}
+ private def addNewChatActor(source: MessageSource): ActorRef = {
+ val actor = authActorFactory(source)
+ chats += source -> actor
+ actor
+ }
+
private def destroyChat(source: MessageSource): Unit = {
LOG.info(s"Destroying chat for $source due to $idleTimeout inactivity")
timers.remove(source)
+ removeChat(source)
+ }
+
+ private def switchUser(userId: Login.UserId): Unit = {
+ removeChat(userId.source)
+ addNewChatActor(userId.source)
+ }
+
+ private def removeChat(source: MessageSource): Unit = {
chats.remove(source).foreach(_ ! PoisonPill)
}
diff --git a/server/src/main/scala/com/lbs/server/actor/Visits.scala b/server/src/main/scala/com/lbs/server/actor/Visits.scala
index 457b592..bbbc6fb 100644
--- a/server/src/main/scala/com/lbs/server/actor/Visits.scala
+++ b/server/src/main/scala/com/lbs/server/actor/Visits.scala
@@ -42,7 +42,7 @@ class Visits(val userId: UserId, bot: Bot, apiService: ApiService, val localizat
whenSafe(RequestData) {
case Event(Next, _) =>
- val visits = apiService.reservedVisits(userId.userId)
+ val visits = apiService.reservedVisits(userId.accountId)
reservedVisitsPager ! visits
goto(AwaitPage)
}
@@ -65,7 +65,7 @@ class Visits(val userId: UserId, bot: Bot, apiService: ApiService, val localizat
bot.sendMessage(userId.source, lang.appointmentWasNotCancelled)
goto(RequestData)
case Event(Command(_, _, Some(Tags.Yes)), visit: ReservedVisit) =>
- apiService.deleteReservation(userId.userId, visit.reservationId) match {
+ apiService.deleteReservation(userId.accountId, visit.reservationId) match {
case Left(ex) => bot.sendMessage(userId.source, lang.unableToCancelUpcomingVisit(ex.getMessage))
case Right(r) => bot.sendMessage(userId.source, lang.appointmentHasBeenCancelled)
}
diff --git a/server/src/main/scala/com/lbs/server/lang/En.scala b/server/src/main/scala/com/lbs/server/lang/En.scala
index 3d79000..362e8ca 100644
--- a/server/src/main/scala/com/lbs/server/lang/En.scala
+++ b/server/src/main/scala/com/lbs/server/lang/En.scala
@@ -1,26 +1,26 @@
/**
- * MIT License
- *
- * Copyright (c) 2018 Yevhen Zadyra
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
+ * MIT License
+ *
+ * Copyright (c) 2018 Yevhen Zadyra
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
package com.lbs.server.lang
import java.time.ZonedDateTime
@@ -353,4 +353,13 @@ object En extends Lang {
override def allDay: String = "All day"
override def preferredTimeIs(time: Int): String = s"⏱ Preferred time is ${timeOfDay(time)}"
+
+ override def deleteAccount: String = "➖ Delete account"
+
+ override def addAccount: String = "➕ Add account"
+
+ override def accountSwitched(username: String): String =
+ s"✅ Account has been switched to $username"
+
+ override def pleaseChooseAccount: String = "➡ Please choose an action or select account"
}
diff --git a/server/src/main/scala/com/lbs/server/lang/Lang.scala b/server/src/main/scala/com/lbs/server/lang/Lang.scala
index 268fe8f..7cc7527 100644
--- a/server/src/main/scala/com/lbs/server/lang/Lang.scala
+++ b/server/src/main/scala/com/lbs/server/lang/Lang.scala
@@ -1,26 +1,26 @@
/**
- * MIT License
- *
- * Copyright (c) 2018 Yevhen Zadyra
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
+ * MIT License
+ *
+ * Copyright (c) 2018 Yevhen Zadyra
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
package com.lbs.server.lang
import java.time.ZonedDateTime
@@ -233,4 +233,12 @@ trait Lang {
def allDay: String
def preferredTimeIs(time: Int): String
+
+ def deleteAccount: String
+
+ def addAccount: String
+
+ def pleaseChooseAccount: String
+
+ def accountSwitched(username: String): String
}
diff --git a/server/src/main/scala/com/lbs/server/lang/Ua.scala b/server/src/main/scala/com/lbs/server/lang/Ua.scala
index 3d872ef..4857029 100644
--- a/server/src/main/scala/com/lbs/server/lang/Ua.scala
+++ b/server/src/main/scala/com/lbs/server/lang/Ua.scala
@@ -1,26 +1,26 @@
/**
- * MIT License
- *
- * Copyright (c) 2018 Yevhen Zadyra
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
+ * MIT License
+ *
+ * Copyright (c) 2018 Yevhen Zadyra
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
package com.lbs.server.lang
import java.time.ZonedDateTime
@@ -352,4 +352,13 @@ object Ua extends Lang {
override def allDay: String = "Весь день"
override def preferredTimeIs(time: Int): String = s"⏱ Бажаний час ${timeOfDay(time)}"
+
+ override def deleteAccount: String = "➖ Видалити акаунт"
+
+ override def addAccount: String = "➕ Додати акаунт"
+
+ override def accountSwitched(username: String): String =
+ s"✅ Аккаунт було переключено на $username"
+
+ override def pleaseChooseAccount: String = "➡ Будь ласка, оберіть дію або виберіть акаунт"
}
diff --git a/server/src/main/scala/com/lbs/server/repository/DataRepository.scala b/server/src/main/scala/com/lbs/server/repository/DataRepository.scala
index d6dfea7..96f4671 100644
--- a/server/src/main/scala/com/lbs/server/repository/DataRepository.scala
+++ b/server/src/main/scala/com/lbs/server/repository/DataRepository.scala
@@ -1,31 +1,31 @@
/**
- * MIT License
- *
- * Copyright (c) 2018 Yevhen Zadyra
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
+ * MIT License
+ *
+ * Copyright (c) 2018 Yevhen Zadyra
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
package com.lbs.server.repository
import java.time.ZonedDateTime
-import com.lbs.server.repository.model.{Bug, CityHistory, ClinicHistory, Credentials, DoctorHistory, JLong, Monitoring, ServiceHistory, Settings, Source}
+import com.lbs.server.repository.model.{Bug, CityHistory, ClinicHistory, Credentials, DoctorHistory, JLong, Monitoring, ServiceHistory, Settings, Source, SystemUser}
import javax.persistence.EntityManager
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Repository
@@ -37,48 +37,48 @@ class DataRepository(@Autowired em: EntityManager) {
private val maxHistory = 2
- def getCityHistory(userId: Long): Seq[CityHistory] = {
+ def getCityHistory(accountId: Long): Seq[CityHistory] = {
em.createQuery(
"""select city from CityHistory city where city.recordId in
- | (select max(c.recordId) from CityHistory c where c.userId = :userId group by c.name order by MAX(c.time) desc)
+ | (select max(c.recordId) from CityHistory c where c.accountId = :accountId group by c.name order by MAX(c.time) desc)
| order by city.time desc""".stripMargin, classOf[CityHistory])
- .setParameter("userId", userId)
+ .setParameter("accountId", accountId)
.setMaxResults(maxHistory)
.getResultList.asScala
}
- def getClinicHistory(userId: Long, cityId: Long): Seq[ClinicHistory] = {
+ def getClinicHistory(accountId: Long, cityId: Long): Seq[ClinicHistory] = {
em.createQuery(
"""select clinic from ClinicHistory clinic where clinic.recordId in
- | (select max(c.recordId) from ClinicHistory c where c.userId = :userId and c.cityId = :cityId group by c.name order by MAX(c.time) desc)
+ | (select max(c.recordId) from ClinicHistory c where c.accountId = :accountId and c.cityId = :cityId group by c.name order by MAX(c.time) desc)
| order by clinic.time desc""".stripMargin, classOf[ClinicHistory])
- .setParameter("userId", userId)
+ .setParameter("accountId", accountId)
.setParameter("cityId", cityId)
.setMaxResults(maxHistory)
.getResultList.asScala
}
- def getServiceHistory(userId: Long, cityId: Long, clinicId: Option[Long]): Seq[ServiceHistory] = {
+ def getServiceHistory(accountId: Long, cityId: Long, clinicId: Option[Long]): Seq[ServiceHistory] = {
val query = em.createQuery(
s"""select service from ServiceHistory service where service.recordId in
- | (select max(s.recordId) from ServiceHistory s where s.userId = :userId and s.cityId = :cityId
+ | (select max(s.recordId) from ServiceHistory s where s.accountId = :accountId and s.cityId = :cityId
| and s.clinicId ${clinicId.map(_ => "= :clinicId").getOrElse("IS NULL")} group by s.name order by MAX(s.time) desc)
| order by service.time desc""".stripMargin, classOf[ServiceHistory])
- .setParameter("userId", userId)
+ .setParameter("accountId", accountId)
.setParameter("cityId", cityId)
.setMaxResults(maxHistory)
clinicId.map(id => query.setParameter("clinicId", id)).getOrElse(query).getResultList.asScala
}
- def getDoctorHistory(userId: Long, cityId: Long, clinicId: Option[Long], serviceId: Long): Seq[DoctorHistory] = {
+ def getDoctorHistory(accountId: Long, cityId: Long, clinicId: Option[Long], serviceId: Long): Seq[DoctorHistory] = {
val query = em.createQuery(
s"""select doctor from DoctorHistory doctor where doctor.recordId in
- | (select max(d.recordId) from DoctorHistory d where d.userId = :userId
+ | (select max(d.recordId) from DoctorHistory d where d.accountId = :accountId
| and d.cityId = :cityId and d.clinicId ${clinicId.map(_ => "= :clinicId").getOrElse("IS NULL")}
| and d.serviceId = :serviceId group by d.name order by MAX(d.time) desc)
| order by doctor.time desc""".stripMargin, classOf[DoctorHistory])
- .setParameter("userId", userId)
+ .setParameter("accountId", accountId)
.setParameter("cityId", cityId)
.setParameter("serviceId", serviceId)
.setMaxResults(maxHistory)
@@ -86,10 +86,10 @@ class DataRepository(@Autowired em: EntityManager) {
clinicId.map(id => query.setParameter("clinicId", id)).getOrElse(query).getResultList.asScala
}
- def findCredentials(userId: Long): Option[Credentials] = {
+ def findCredentials(accountId: Long): Option[Credentials] = {
em.createQuery(
- "select credentials from Credentials credentials where credentials.userId = :userId", classOf[Credentials])
- .setParameter("userId", userId)
+ "select credentials from Credentials credentials where credentials.accountId = :accountId", classOf[Credentials])
+ .setParameter("accountId", accountId)
.getResultList.asScala.headOption
}
@@ -107,29 +107,29 @@ class DataRepository(@Autowired em: EntityManager) {
.getResultList.asScala
}
- def getActiveMonitoringsCount(userId: Long): JLong = {
+ def getActiveMonitoringsCount(accountId: Long): JLong = {
em.createQuery(
"""select count(monitoring) from Monitoring monitoring where monitoring.active = true
- | and monitoring.userId = :userId""".stripMargin, classOf[JLong])
- .setParameter("userId", userId)
+ | and monitoring.accountId = :accountId""".stripMargin, classOf[JLong])
+ .setParameter("accountId", accountId)
.getSingleResult
}
- def getActiveMonitorings(userId: Long): Seq[Monitoring] = {
+ def getActiveMonitorings(accountId: Long): Seq[Monitoring] = {
em.createQuery(
"""select monitoring from Monitoring monitoring where monitoring.active = true
- | and monitoring.userId = :userId order by monitoring.dateTo asc""".stripMargin, classOf[Monitoring])
- .setParameter("userId", userId)
+ | and monitoring.accountId = :accountId order by monitoring.dateTo asc""".stripMargin, classOf[Monitoring])
+ .setParameter("accountId", accountId)
.getResultList.asScala
}
- def findActiveMonitoring(userId: Long, cityId: Long, serviceId: Long): Option[Monitoring] = {
+ def findActiveMonitoring(accountId: Long, cityId: Long, serviceId: Long): Option[Monitoring] = {
em.createQuery(
"""select monitoring from Monitoring monitoring where monitoring.active = true
- | and monitoring.userId = :userId
+ | and monitoring.accountId = :accountId
| and monitoring.cityId = :cityId
| and monitoring.serviceId = :serviceId""".stripMargin, classOf[Monitoring])
- .setParameter("userId", userId)
+ .setParameter("accountId", accountId)
.setParameter("cityId", cityId)
.setParameter("serviceId", serviceId)
.getResultList.asScala.headOption
@@ -143,11 +143,11 @@ class DataRepository(@Autowired em: EntityManager) {
.getResultList.asScala
}
- def findMonitoring(userId: Long, monitoringId: Long): Option[Monitoring] = {
+ def findMonitoring(accountId: Long, monitoringId: Long): Option[Monitoring] = {
em.createQuery(
- """select monitoring from Monitoring monitoring where monitoring.userId = :userId
+ """select monitoring from Monitoring monitoring where monitoring.accountId = :accountId
| and monitoring.recordId = :monitoringId""".stripMargin, classOf[Monitoring])
- .setParameter("userId", userId)
+ .setParameter("accountId", accountId)
.setParameter("monitoringId", monitoringId)
.getResultList.asScala.headOption
}
@@ -186,6 +186,46 @@ class DataRepository(@Autowired em: EntityManager) {
.getResultList.asScala.headOption
}
+ def findUserIdBySource(chatId: String, sourceSystemId: Long): Option[JLong] = {
+ em.createQuery(
+ "select source.userId from Source source where source.chatId = :chatId" +
+ " and source.sourceSystemId = :sourceSystemId", classOf[JLong])
+ .setParameter("chatId", chatId)
+ .setParameter("sourceSystemId", sourceSystemId)
+ .getResultList.asScala.headOption
+ }
+
+ def findAccountId(userId: Long): Option[JLong] = {
+ em.createQuery(
+ "select systemUser.activeAccountId from SystemUser systemUser where systemUser.recordId = :recordId", classOf[JLong])
+ .setParameter("recordId", userId)
+ .getResultList.asScala.headOption
+ }
+
+ def findUser(userId: Long): Option[SystemUser] = {
+ em.createQuery(
+ "select systemUser from SystemUser systemUser where systemUser.recordId = :recordId", classOf[SystemUser])
+ .setParameter("recordId", userId)
+ .getResultList.asScala.headOption
+ }
+
+ def getUserCredentials(userId: Long): Seq[Credentials] = {
+ em.createQuery(
+ "select credentials from Credentials credentials where credentials.userId = :userId", classOf[Credentials])
+ .setParameter("userId", userId)
+ .getResultList.asScala
+ }
+
+ def findUserCredentialsByUserIdAndAccountId(userId: Long, accountId: Long): Option[Credentials] = {
+ em.createQuery(
+ """select credentials from Credentials credentials where credentials.userId = :userId
+ | and credentials.accountId = :accountId
+ """.stripMargin, classOf[Credentials])
+ .setParameter("userId", userId)
+ .setParameter("accountId", accountId)
+ .getResultList.asScala.headOption
+ }
+
def saveEntity[T](entity: T): T = {
em.merge(entity)
}
diff --git a/server/src/main/scala/com/lbs/server/repository/model/Account.scala b/server/src/main/scala/com/lbs/server/repository/model/Account.scala
new file mode 100644
index 0000000..ff4c084
--- /dev/null
+++ b/server/src/main/scala/com/lbs/server/repository/model/Account.scala
@@ -0,0 +1,31 @@
+/**
+ * MIT License
+ *
+ * Copyright (c) 2018 Yevhen Zadyra
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package com.lbs.server.repository.model
+
+import javax.persistence._
+
+@Entity
+@Access(AccessType.FIELD)
+//just a sequence generator
+class Account extends RecordId
\ No newline at end of file
diff --git a/server/src/main/scala/com/lbs/server/repository/model/CityHistory.scala b/server/src/main/scala/com/lbs/server/repository/model/CityHistory.scala
index d373ced..d434e8a 100644
--- a/server/src/main/scala/com/lbs/server/repository/model/CityHistory.scala
+++ b/server/src/main/scala/com/lbs/server/repository/model/CityHistory.scala
@@ -41,8 +41,8 @@ class CityHistory extends History with RecordId {
var name: String = _
@BeanProperty
- @Column(name = "user_id", nullable = false)
- var userId: JLong = _
+ @Column(name = "account_id", nullable = false)
+ var accountId: JLong = _
@BeanProperty
@Column(nullable = false)
@@ -50,9 +50,9 @@ class CityHistory extends History with RecordId {
}
object CityHistory {
- def apply(userId: Long, id: Long, name: String, time: ZonedDateTime): CityHistory = {
+ def apply(accountId: Long, id: Long, name: String, time: ZonedDateTime): CityHistory = {
val city = new CityHistory
- city.userId = userId
+ city.accountId = accountId
city.id = id
city.name = name
city.time = time
diff --git a/server/src/main/scala/com/lbs/server/repository/model/ClinicHistory.scala b/server/src/main/scala/com/lbs/server/repository/model/ClinicHistory.scala
index 9995348..8fcf6e7 100644
--- a/server/src/main/scala/com/lbs/server/repository/model/ClinicHistory.scala
+++ b/server/src/main/scala/com/lbs/server/repository/model/ClinicHistory.scala
@@ -41,8 +41,8 @@ class ClinicHistory extends History with RecordId {
var name: String = _
@BeanProperty
- @Column(name = "user_id", nullable = false)
- var userId: JLong = _
+ @Column(name = "account_id", nullable = false)
+ var accountId: JLong = _
@BeanProperty
@Column(name = "city_id", nullable = false)
@@ -54,9 +54,9 @@ class ClinicHistory extends History with RecordId {
}
object ClinicHistory {
- def apply(userId: Long, id: Long, name: String, cityId: Long, time: ZonedDateTime): ClinicHistory = {
+ def apply(accountId: Long, id: Long, name: String, cityId: Long, time: ZonedDateTime): ClinicHistory = {
val clinic = new ClinicHistory
- clinic.userId = userId
+ clinic.accountId = accountId
clinic.id = id
clinic.name = name
clinic.time = time
diff --git a/server/src/main/scala/com/lbs/server/repository/model/Credentials.scala b/server/src/main/scala/com/lbs/server/repository/model/Credentials.scala
index e0cd62c..2db8832 100644
--- a/server/src/main/scala/com/lbs/server/repository/model/Credentials.scala
+++ b/server/src/main/scala/com/lbs/server/repository/model/Credentials.scala
@@ -1,26 +1,26 @@
/**
- * MIT License
- *
- * Copyright (c) 2018 Yevhen Zadyra
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
+ * MIT License
+ *
+ * Copyright (c) 2018 Yevhen Zadyra
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
package com.lbs.server.repository.model
import javax.persistence._
@@ -29,12 +29,15 @@ import scala.beans.BeanProperty
@Entity
@Access(AccessType.FIELD)
-class Credentials {
- @Id
+class Credentials extends RecordId {
@BeanProperty
@Column(name = "user_id", nullable = false)
var userId: JLong = _
+ @BeanProperty
+ @Column(name = "account_id", nullable = false)
+ var accountId: JLong = _
+
@BeanProperty
@Column(nullable = false)
var username: String = _
@@ -45,9 +48,10 @@ class Credentials {
}
object Credentials {
- def apply(userId: Long, username: String, password: String): Credentials = {
+ def apply(userId: JLong, accountId: JLong, username: String, password: String): Credentials = {
val credentials = new Credentials
credentials.userId = userId
+ credentials.accountId = accountId
credentials.username = username
credentials.password = password
credentials
diff --git a/server/src/main/scala/com/lbs/server/repository/model/DoctorHistory.scala b/server/src/main/scala/com/lbs/server/repository/model/DoctorHistory.scala
index 2b31fe8..64ac3fc 100644
--- a/server/src/main/scala/com/lbs/server/repository/model/DoctorHistory.scala
+++ b/server/src/main/scala/com/lbs/server/repository/model/DoctorHistory.scala
@@ -41,8 +41,8 @@ class DoctorHistory extends History with RecordId {
var name: String = _
@BeanProperty
- @Column(name = "user_id", nullable = false)
- var userId: JLong = _
+ @Column(name = "account_id", nullable = false)
+ var accountId: JLong = _
@BeanProperty
@Column(name = "city_id", nullable = false)
@@ -62,9 +62,9 @@ class DoctorHistory extends History with RecordId {
}
object DoctorHistory {
- def apply(userId: Long, id: Long, name: String, cityId: Long, clinicId: Option[Long], serviceId: Long, time: ZonedDateTime): DoctorHistory = {
+ def apply(accountId: Long, id: Long, name: String, cityId: Long, clinicId: Option[Long], serviceId: Long, time: ZonedDateTime): DoctorHistory = {
val doctor = new DoctorHistory
- doctor.userId = userId
+ doctor.accountId = accountId
doctor.id = id
doctor.name = name
doctor.time = time
diff --git a/server/src/main/scala/com/lbs/server/repository/model/Monitoring.scala b/server/src/main/scala/com/lbs/server/repository/model/Monitoring.scala
index f18486c..53dfa47 100644
--- a/server/src/main/scala/com/lbs/server/repository/model/Monitoring.scala
+++ b/server/src/main/scala/com/lbs/server/repository/model/Monitoring.scala
@@ -1,26 +1,26 @@
/**
- * MIT License
- *
- * Copyright (c) 2018 Yevhen Zadyra
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
+ * MIT License
+ *
+ * Copyright (c) 2018 Yevhen Zadyra
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
package com.lbs.server.repository.model
import java.time.ZonedDateTime
@@ -36,6 +36,9 @@ class Monitoring extends RecordId {
@Column(name = "user_id", nullable = false)
var userId: JLong = _
+ @BeanProperty
+ @Column(name = "account_id", nullable = false)
+ var accountId: JLong = _
@BeanProperty
@Column(name = "chat_id", nullable = false)
@@ -103,12 +106,13 @@ class Monitoring extends RecordId {
}
object Monitoring {
- def apply(userId: Long, chatId: String, sourceSystemId: Long, cityId: Long, cityName: String, clinicId: Option[Long], clinicName: String,
+ def apply(userId: Long, accountId: Long, chatId: String, sourceSystemId: Long, cityId: Long, cityName: String, clinicId: Option[Long], clinicName: String,
serviceId: Long, serviceName: String, doctorId: Option[Long], doctorName: String, dateFrom: ZonedDateTime,
dateTo: ZonedDateTime, autobook: Boolean = false, created: ZonedDateTime = ZonedDateTime.now(), timeOfDay: Int,
active: Boolean = true): Monitoring = {
val monitoring = new Monitoring
monitoring.userId = userId
+ monitoring.accountId = accountId
monitoring.chatId = chatId
monitoring.sourceSystemId = sourceSystemId
monitoring.cityId = cityId
diff --git a/server/src/main/scala/com/lbs/server/repository/model/ServiceHistory.scala b/server/src/main/scala/com/lbs/server/repository/model/ServiceHistory.scala
index 17728fe..f009322 100644
--- a/server/src/main/scala/com/lbs/server/repository/model/ServiceHistory.scala
+++ b/server/src/main/scala/com/lbs/server/repository/model/ServiceHistory.scala
@@ -41,8 +41,8 @@ class ServiceHistory extends History with RecordId {
var name: String = _
@BeanProperty
- @Column(name = "userId_id", nullable = false)
- var userId: JLong = _
+ @Column(name = "account_id", nullable = false)
+ var accountId: JLong = _
@BeanProperty
@Column(name = "city_id", nullable = false)
@@ -58,9 +58,9 @@ class ServiceHistory extends History with RecordId {
}
object ServiceHistory {
- def apply(userId: Long, id: Long, name: String, cityId: Long, clinicId: Option[Long], time: ZonedDateTime): ServiceHistory = {
+ def apply(accountId: Long, id: Long, name: String, cityId: Long, clinicId: Option[Long], time: ZonedDateTime): ServiceHistory = {
val service = new ServiceHistory
- service.userId = userId
+ service.accountId = accountId
service.id = id
service.name = name
service.time = time
diff --git a/server/src/main/scala/com/lbs/server/repository/model/SystemUser.scala b/server/src/main/scala/com/lbs/server/repository/model/SystemUser.scala
index fd2cce7..3517f53 100644
--- a/server/src/main/scala/com/lbs/server/repository/model/SystemUser.scala
+++ b/server/src/main/scala/com/lbs/server/repository/model/SystemUser.scala
@@ -1,34 +1,44 @@
/**
- * MIT License
- *
- * Copyright (c) 2018 Yevhen Zadyra
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
+ * MIT License
+ *
+ * Copyright (c) 2018 Yevhen Zadyra
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
package com.lbs.server.repository.model
import javax.persistence._
+import scala.beans.BeanProperty
+
@Entity
@Access(AccessType.FIELD)
-class SystemUser extends RecordId
-
-
-
+class SystemUser extends RecordId {
+ @BeanProperty
+ @Column(name = "active_account_id", nullable = false)
+ var activeAccountId: JLong = _
+}
+object SystemUser {
+ def apply(activeAccountId: Long): SystemUser = {
+ val user = new SystemUser
+ user.activeAccountId = activeAccountId
+ user
+ }
+}
\ No newline at end of file
diff --git a/server/src/main/scala/com/lbs/server/service/ApiService.scala b/server/src/main/scala/com/lbs/server/service/ApiService.scala
index 718b7ed..a6e4e31 100644
--- a/server/src/main/scala/com/lbs/server/service/ApiService.scala
+++ b/server/src/main/scala/com/lbs/server/service/ApiService.scala
@@ -40,53 +40,53 @@ class ApiService extends SessionSupport {
@Autowired
private var textEncryptor: TextEncryptor = _
- def getAllCities(userId: Long): Either[Throwable, List[IdName]] =
- withSession(userId) { session =>
+ def getAllCities(accountId: Long): Either[Throwable, List[IdName]] =
+ withSession(accountId) { session =>
LuxmedApi.reservationFilter(session.accessToken, session.tokenType).map(_.cities)
}
- def getAllClinics(userId: Long, cityId: Long): Either[Throwable, List[IdName]] =
- withSession(userId) { session =>
+ def getAllClinics(accountId: Long, cityId: Long): Either[Throwable, List[IdName]] =
+ withSession(accountId) { session =>
LuxmedApi.reservationFilter(session.accessToken,
session.tokenType, cityId = Some(cityId)).map(_.clinics)
}
- def getAllServices(userId: Long, cityId: Long, clinicId: Option[Long]): Either[Throwable, List[IdName]] =
- withSession(userId) { session =>
+ def getAllServices(accountId: Long, cityId: Long, clinicId: Option[Long]): Either[Throwable, List[IdName]] =
+ withSession(accountId) { session =>
LuxmedApi.reservationFilter(session.accessToken,
session.tokenType, cityId = Some(cityId),
clinicId = clinicId).map(_.services)
}
- def getAllDoctors(userId: Long, cityId: Long, clinicId: Option[Long], serviceId: Long): Either[Throwable, List[IdName]] =
- withSession(userId) { session =>
+ def getAllDoctors(accountId: Long, cityId: Long, clinicId: Option[Long], serviceId: Long): Either[Throwable, List[IdName]] =
+ withSession(accountId) { session =>
LuxmedApi.reservationFilter(session.accessToken,
session.tokenType, cityId = Some(cityId),
clinicId = clinicId, serviceId = Some(serviceId)).map(_.doctors)
}
- def getDefaultPayer(userId: Long, cityId: Long, clinicId: Option[Long], serviceId: Long): Either[Throwable, Option[IdName]] =
- withSession(userId) { session =>
+ def getDefaultPayer(accountId: Long, cityId: Long, clinicId: Option[Long], serviceId: Long): Either[Throwable, Option[IdName]] =
+ withSession(accountId) { session =>
LuxmedApi.reservationFilter(session.accessToken,
session.tokenType, cityId = Some(cityId),
clinicId = clinicId, serviceId = Some(serviceId)).map(_.defaultPayer)
}
- def getAvailableTerms(userId: Long, cityId: Long, clinicId: Option[Long], serviceId: Long, doctorId: Option[Long],
+ def getAvailableTerms(accountId: Long, cityId: Long, clinicId: Option[Long], serviceId: Long, doctorId: Option[Long],
fromDate: ZonedDateTime = ZonedDateTime.now(), toDate: Option[ZonedDateTime] = None, timeOfDay: Int = 0,
languageId: Long = 10, findFirstFreeTerm: Boolean = false): Either[Throwable, List[AvailableVisitsTermPresentation]] =
- getDefaultPayer(userId, cityId, clinicId, serviceId).flatMap {
+ getDefaultPayer(accountId, cityId, clinicId, serviceId).flatMap {
case Some(payerId) =>
- withSession(userId) { session =>
+ withSession(accountId) { session =>
LuxmedApi.availableTerms(session.accessToken, session.tokenType, payerId.id, cityId, clinicId, serviceId, doctorId,
fromDate, toDate, timeOfDay, languageId, findFirstFreeTerm).map(_.availableVisitsTermPresentation)
}
- case None => sys.error(s"Can't determine payer id by user: $userId, city: $cityId, clinic: $clinicId, service: $serviceId")
+ case None => sys.error(s"Can't determine payer id by user: $accountId, city: $cityId, clinic: $clinicId, service: $serviceId")
}
- def temporaryReservation(userId: Long, temporaryReservationRequest: TemporaryReservationRequest, valuationsRequest: ValuationsRequest): Either[Throwable, (TemporaryReservationResponse, ValuationsResponse)] =
- withSession(userId) { session =>
+ def temporaryReservation(accountId: Long, temporaryReservationRequest: TemporaryReservationRequest, valuationsRequest: ValuationsRequest): Either[Throwable, (TemporaryReservationResponse, ValuationsResponse)] =
+ withSession(accountId) { session =>
LuxmedApi.temporaryReservation(session.accessToken, session.tokenType, temporaryReservationRequest) match {
case Left(ex) => Left(ex)
case Right(temporaryReservation) =>
@@ -97,30 +97,30 @@ class ApiService extends SessionSupport {
}
}
- def deleteTemporaryReservation(userId: Long, temporaryReservationId: Long): Either[Throwable, HttpResponse[String]] =
- withSession(userId) { session =>
+ def deleteTemporaryReservation(accountId: Long, temporaryReservationId: Long): Either[Throwable, HttpResponse[String]] =
+ withSession(accountId) { session =>
LuxmedApi.deleteTemporaryReservation(session.accessToken, session.tokenType, temporaryReservationId)
}
- def reservation(userId: Long, reservationRequest: ReservationRequest): Either[Throwable, ReservationResponse] =
- withSession(userId) { session =>
+ def reservation(accountId: Long, reservationRequest: ReservationRequest): Either[Throwable, ReservationResponse] =
+ withSession(accountId) { session =>
LuxmedApi.reservation(session.accessToken, session.tokenType, reservationRequest)
}
- def visitsHistory(userId: 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]] =
- withSession(userId) { session =>
+ withSession(accountId) { session =>
LuxmedApi.visitsHistory(session.accessToken, session.tokenType, fromDate, toDate, page, pageSize).map(_.historicVisits)
}
- def reservedVisits(userId: Long, fromDate: ZonedDateTime = ZonedDateTime.now(),
+ def reservedVisits(accountId: Long, fromDate: ZonedDateTime = ZonedDateTime.now(),
toDate: ZonedDateTime = ZonedDateTime.now().plusMonths(3)): Either[Throwable, List[ReservedVisit]] =
- withSession(userId) { session =>
+ withSession(accountId) { session =>
LuxmedApi.reservedVisits(session.accessToken, session.tokenType, fromDate, toDate).map(_.reservedVisits)
}
- def deleteReservation(userId: Long, reservationId: Long): Either[Throwable, HttpResponse[String]] =
- withSession(userId) { session =>
+ def deleteReservation(accountId: Long, reservationId: Long): Either[Throwable, HttpResponse[String]] =
+ withSession(accountId) { session =>
LuxmedApi.deleteReservation(session.accessToken, session.tokenType, reservationId)
}
diff --git a/server/src/main/scala/com/lbs/server/service/DataService.scala b/server/src/main/scala/com/lbs/server/service/DataService.scala
index 0d45055..0425e24 100644
--- a/server/src/main/scala/com/lbs/server/service/DataService.scala
+++ b/server/src/main/scala/com/lbs/server/service/DataService.scala
@@ -1,26 +1,26 @@
/**
- * MIT License
- *
- * Copyright (c) 2018 Yevhen Zadyra
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
+ * MIT License
+ *
+ * Copyright (c) 2018 Yevhen Zadyra
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
package com.lbs.server.service
import java.time.ZonedDateTime
@@ -39,10 +39,10 @@ import org.springframework.stereotype.Service
class DataService {
@Autowired
- private var dataRepository: DataRepository = _
+ private[service] var dataRepository: DataRepository = _
- def getLatestCities(userId: Long): Seq[IdName] = {
- dataRepository.getCityHistory(userId).mapTo[IdName]
+ def getLatestCities(accountId: Long): Seq[IdName] = {
+ dataRepository.getCityHistory(accountId).mapTo[IdName]
}
def getLatestClinicsByCityId(userId: Long, cityId: Long): Seq[IdName] = {
@@ -57,8 +57,8 @@ class DataService {
dataRepository.getDoctorHistory(userId, cityId, clinicId, serviceId).mapTo[IdName]
}
- def getCredentials(userId: Long): Option[Credentials] = {
- dataRepository.findCredentials(userId)
+ def getCredentials(accountId: Long): Option[Credentials] = {
+ dataRepository.findCredentials(accountId)
}
@Transactional
@@ -79,38 +79,56 @@ class DataService {
dataRepository.getActiveMonitorings
}
- def getActiveMonitoringsCount(userId: Long): Long = {
- dataRepository.getActiveMonitoringsCount(userId)
+ def getActiveMonitoringsCount(accountId: Long): Long = {
+ dataRepository.getActiveMonitoringsCount(accountId)
}
- def getActiveMonitorings(userId: Long): Seq[Monitoring] = {
- dataRepository.getActiveMonitorings(userId)
+ def getActiveMonitorings(accountId: Long): Seq[Monitoring] = {
+ dataRepository.getActiveMonitorings(accountId)
}
- def findActiveMonitoring(userId: Long, cityId: Long, serviceId: Long): Option[Monitoring] = {
- dataRepository.findActiveMonitoring(userId, cityId, serviceId)
+ def findActiveMonitoring(accountId: Long, cityId: Long, serviceId: Long): Option[Monitoring] = {
+ dataRepository.findActiveMonitoring(accountId, cityId, serviceId)
}
def getActiveMonitoringsSince(since: ZonedDateTime): Seq[Monitoring] = {
dataRepository.getActiveMonitoringsSince(since)
}
- def findMonitoring(userId: Long, monitoringId: Long): Option[Monitoring] = {
- dataRepository.findMonitoring(userId, monitoringId)
+ def findMonitoring(accountId: Long, monitoringId: Long): Option[Monitoring] = {
+ dataRepository.findMonitoring(accountId, monitoringId)
}
def findSettings(userId: Long): Option[Settings] = {
dataRepository.findSettings(userId)
}
- def findUserIdBySource(source: MessageSource): Option[Long] = {
- dataRepository.findUserId(source.chatId, source.sourceSystem.id).map(_.toLong)
+ def findUserAndAccountIdBySource(source: MessageSource): Option[(Long, Long)] = {
+ val userIdMaybe = dataRepository.findUserId(source.chatId, source.sourceSystem.id).map(_.toLong)
+ userIdMaybe.flatMap(userId => dataRepository.findAccountId(userId).map(_.toLong).map(accountId => userId -> accountId))
}
def findCredentialsByUsername(username: String): Option[Credentials] = {
dataRepository.findCredentialsByUsername(username)
}
+ def getUserCredentials(userId: Long): Seq[Credentials] = {
+ dataRepository.getUserCredentials(userId)
+ }
+
+ def findUserCredentialsByAccountId(userId: Long, accountId: Long): Option[Credentials] = {
+ dataRepository.findUserCredentialsByUserIdAndAccountId(userId, accountId)
+ }
+
+ def findUser(userId: Long): Option[SystemUser] = {
+ dataRepository.findUser(userId)
+ }
+
+ @Transactional
+ def saveUser(user: SystemUser): SystemUser = {
+ dataRepository.saveEntity(user)
+ }
+
@Transactional
def saveSettings(settings: Settings): Settings = {
dataRepository.saveEntity(settings)
@@ -128,36 +146,63 @@ class DataService {
val src = Source(source.chatId, source.sourceSystem.id, credentials.userId)
dataRepository.saveEntity(src)
}
+ val userMaybe = dataRepository.findUser(credentials.userId)
+ userMaybe match {
+ case Some(user) =>
+ user.activeAccountId = credentials.accountId
+ dataRepository.saveEntity(user)
+ case None => sys.error(s"Strange, but user [#${credentials.userId}] not found")
+ }
credentials.username = username
credentials.password = password
dataRepository.saveEntity(credentials)
- case None => //new user
- val user = dataRepository.saveEntity(new SystemUser)
- val src = Source(source.chatId, source.sourceSystem.id, user.recordId)
- dataRepository.saveEntity(src)
- val credentials = Credentials(user.recordId, username, password)
- dataRepository.saveEntity(credentials)
+ case None => //new user or new account?
+ val userMaybe = dataRepository.findUserIdBySource(source.chatId, source.sourceSystem.id).flatMap {
+ userId => dataRepository.findUser(userId)
+ }
+ userMaybe match {
+ case Some(user) => //user already exists, this is just the new credentials
+ val account = dataRepository.saveEntity(new Account)
+ user.activeAccountId = account.recordId
+ dataRepository.saveEntity(user)
+ val sourceMaybe = dataRepository.findSource(source.chatId, source.sourceSystem.id, user.recordId)
+ sourceMaybe match {
+ case Some(_) => //source already exists. Just save credentials
+ case None => //add new source
+ val src = Source(source.chatId, source.sourceSystem.id, user.recordId)
+ dataRepository.saveEntity(src)
+ }
+ val credentials = Credentials(user.recordId, account.recordId, username, password)
+ dataRepository.saveEntity(credentials)
+ case None => //everything is new
+ val account = dataRepository.saveEntity(new Account)
+ val user = dataRepository.saveEntity(SystemUser(account.recordId))
+ val src = Source(source.chatId, source.sourceSystem.id, user.recordId)
+ dataRepository.saveEntity(src)
+ val credentials = Credentials(user.recordId, account.recordId, username, password)
+ dataRepository.saveEntity(credentials)
+ }
}
}
@Transactional
- def storeAppointment(userId: Long, bookingData: BookingData): Unit = {
+ def storeAppointment(accountId: Long, bookingData: BookingData): Unit = {
val time = ZonedDateTime.now()
val cityId = bookingData.cityId
val clinicId = bookingData.clinicId
val serviceId = bookingData.serviceId
val doctorId = bookingData.doctorId
- val city = CityHistory(userId, cityId.id, cityId.name, time)
+ val city = CityHistory(accountId, cityId.id, cityId.name, time)
dataRepository.saveEntity(city)
- val clinicMaybe = clinicId.optionalId.map(id => ClinicHistory(userId, id, clinicId.name, cityId.id, time))
+ val clinicMaybe = clinicId.optionalId.map(id => ClinicHistory(accountId, id, clinicId.name, cityId.id, time))
clinicMaybe.foreach(dataRepository.saveEntity)
- val service = ServiceHistory(userId, serviceId.id, serviceId.name, cityId.id, clinicId.optionalId, time)
+ val service = ServiceHistory(accountId, serviceId.id, serviceId.name, cityId.id, clinicId.optionalId, time)
dataRepository.saveEntity(service)
- val doctorMaybe = doctorId.optionalId.map(id => DoctorHistory(userId, id, doctorId.name, cityId.id, clinicId.optionalId, serviceId.id, time))
+ val doctorMaybe = doctorId.optionalId.map(id => DoctorHistory(accountId, id, doctorId.name, cityId.id, clinicId.optionalId, serviceId.id, time))
doctorMaybe.foreach(dataRepository.saveEntity)
}
}
diff --git a/server/src/main/scala/com/lbs/server/service/MonitoringService.scala b/server/src/main/scala/com/lbs/server/service/MonitoringService.scala
index 28d1536..e393a12 100644
--- a/server/src/main/scala/com/lbs/server/service/MonitoringService.scala
+++ b/server/src/main/scala/com/lbs/server/service/MonitoringService.scala
@@ -90,7 +90,7 @@ class MonitoringService extends Logger {
private def monitor(monitoring: Monitoring): Unit = {
LOG.debug(s"Looking for available terms. Monitoring [#${monitoring.recordId}]")
val dateFrom = optimizeDateFrom(monitoring.dateFrom)
- val termsEither = apiService.getAvailableTerms(monitoring.userId, monitoring.cityId, monitoring.clinicId, monitoring.serviceId,
+ val termsEither = apiService.getAvailableTerms(monitoring.accountId, monitoring.cityId, monitoring.clinicId, monitoring.serviceId,
monitoring.doctorId, dateFrom, Some(monitoring.dateTo))
termsEither match {
case Right(terms) =>
@@ -108,7 +108,7 @@ class MonitoringService extends Logger {
case Left(ex: InvalidLoginOrPasswordException) =>
LOG.error(s"User entered invalid name or password. Monitoring will be disabled", ex)
bot.sendMessage(monitoring.source, lang(monitoring.userId).invalidLoginOrPassword)
- val activeUserMonitorings = dataService.getActiveMonitorings(monitoring.userId)
+ val activeUserMonitorings = dataService.getActiveMonitorings(monitoring.accountId)
activeUserMonitorings.foreach { m =>
deactivateMonitoring(m.recordId)
}
@@ -172,12 +172,12 @@ class MonitoringService extends Logger {
val temporaryReservationRequest = term.mapTo[TemporaryReservationRequest]
val valuationsRequest = term.mapTo[ValuationsRequest]
val reservationMaybe = for {
- okResponse <- apiService.temporaryReservation(monitoring.userId, temporaryReservationRequest, valuationsRequest)
+ okResponse <- apiService.temporaryReservation(monitoring.accountId, temporaryReservationRequest, valuationsRequest)
(temporaryReservation, valuations) = okResponse
temporaryReservationId = temporaryReservation.id
visitTermVariant = valuations.visitTermVariants.head
reservationRequest = (temporaryReservationId, visitTermVariant, term).mapTo[ReservationRequest]
- reservation <- apiService.reservation(monitoring.userId, reservationRequest)
+ reservation <- apiService.reservation(monitoring.accountId, reservationRequest)
} yield reservation
reservationMaybe match {
@@ -203,22 +203,22 @@ class MonitoringService extends Logger {
}
def createMonitoring(monitoring: Monitoring): Monitoring = {
- val userMonitoringsCount = dataService.getActiveMonitoringsCount(monitoring.userId)
+ val userMonitoringsCount = dataService.getActiveMonitoringsCount(monitoring.accountId)
require(userMonitoringsCount + 1 <= 5, lang(monitoring.userId).maximumMonitoringsLimitExceeded)
- val activeMonitoring = dataService.findActiveMonitoring(monitoring.userId, monitoring.cityId, monitoring.serviceId)
+ val activeMonitoring = dataService.findActiveMonitoring(monitoring.accountId, monitoring.cityId, monitoring.serviceId)
require(activeMonitoring.isEmpty, lang(monitoring.userId).monitoringOfTheSameTypeExists)
dataService.saveMonitoring(monitoring)
}
- def getActiveMonitorings(userId: Long): Seq[Monitoring] = {
- dataService.getActiveMonitorings(userId)
+ def getActiveMonitorings(accountId: Long): Seq[Monitoring] = {
+ dataService.getActiveMonitorings(accountId)
}
- def bookAppointmentByScheduleId(userId: Long, monitoringId: Long, scheduleId: Long, time: Long): Unit = {
- val monitoringMaybe = dataService.findMonitoring(userId, monitoringId)
+ def bookAppointmentByScheduleId(accountId: Long, monitoringId: Long, scheduleId: Long, time: Long): Unit = {
+ val monitoringMaybe = dataService.findMonitoring(accountId, monitoringId)
monitoringMaybe match {
case Some(monitoring) =>
- val termsEither = apiService.getAvailableTerms(monitoring.userId, monitoring.cityId, monitoring.clinicId, monitoring.serviceId,
+ val termsEither = apiService.getAvailableTerms(monitoring.accountId, monitoring.cityId, monitoring.clinicId, monitoring.serviceId,
monitoring.doctorId, monitoring.dateFrom, Some(monitoring.dateTo))
termsEither match {
case Right(terms) =>
@@ -254,6 +254,7 @@ class MonitoringService extends Logger {
val monitorings = dataService.getActiveMonitorings
LOG.debug(s"Active monitorings found: ${monitorings.length}")
initializeMonitorings(monitorings)
+ disableOutdated()
initializeDbChecker()
}
}
diff --git a/server/src/main/scala/com/lbs/server/service/SessionSupport.scala b/server/src/main/scala/com/lbs/server/service/SessionSupport.scala
index 9919350..554bde7 100644
--- a/server/src/main/scala/com/lbs/server/service/SessionSupport.scala
+++ b/server/src/main/scala/com/lbs/server/service/SessionSupport.scala
@@ -44,26 +44,26 @@ trait SessionSupport {
private val lock = new ParametrizedLock[Long]
- protected def withSession[T](userId: Long)(fn: Session => Either[Throwable, T]): Either[Throwable, T] =
- lock.obtainLock(userId).synchronized {
+ protected def withSession[T](accountId: Long)(fn: Session => Either[Throwable, T]): Either[Throwable, T] =
+ lock.obtainLock(accountId).synchronized {
def auth: Either[Throwable, Session] = {
- val credentialsMaybe = dataService.getCredentials(userId)
+ val credentialsMaybe = dataService.getCredentials(accountId)
credentialsMaybe match {
case Some(credentials) =>
val loginResponse = login(credentials.username, credentials.password)
loginResponse.map(r => Session(r.accessToken, r.tokenType))
- case None => Left(UserNotFoundException(userId))
+ case None => Left(UserNotFoundException(accountId))
}
}
def session: Either[Throwable, Session] = {
- sessions.get(userId) match {
+ sessions.get(accountId) match {
case Some(sess) => Right(sess)
case None =>
auth match {
case Right(sess) =>
- sessions.put(userId, sess)
+ sessions.put(accountId, sess)
Right(sess)
case left => left
}
@@ -74,8 +74,8 @@ trait SessionSupport {
case Right(s) =>
fn(s) match {
case Left(ex) if ex.getMessage.contains("session has expired") =>
- Log.debug(s"The session for user [#$userId] has expired. Try to relogin")
- sessions.remove(userId)
+ Log.debug(s"The session for account [#$accountId] has expired. Try to relogin")
+ sessions.remove(accountId)
session.flatMap(fn)
case another =>
Log.debug(s"Call to remote api function has completed with result:\n$another")
@@ -85,8 +85,8 @@ trait SessionSupport {
}
}
- def addSession(userId: Long, accessToken: String, tokenType: String): Unit =
- lock.obtainLock(userId).synchronized {
- sessions.put(userId, Session(accessToken, tokenType))
+ def addSession(accountId: Long, accessToken: String, tokenType: String): Unit =
+ lock.obtainLock(accountId).synchronized {
+ sessions.put(accountId, Session(accessToken, tokenType))
}
}
diff --git a/server/src/main/scala/com/lbs/server/util/package.scala b/server/src/main/scala/com/lbs/server/util/package.scala
index 186a7a9..c999a06 100644
--- a/server/src/main/scala/com/lbs/server/util/package.scala
+++ b/server/src/main/scala/com/lbs/server/util/package.scala
@@ -1,26 +1,26 @@
/**
- * MIT License
- *
- * Copyright (c) 2018 Yevhen Zadyra
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
+ * MIT License
+ *
+ * Copyright (c) 2018 Yevhen Zadyra
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
package com.lbs.server
import java.time.format.DateTimeFormatter
@@ -49,6 +49,7 @@ package object util {
val (userId, bookingData) = data.asInstanceOf[(UserId, BookingData)]
Monitoring(
userId = userId.userId,
+ accountId = userId.accountId,
chatId = userId.source.chatId,
sourceSystemId = userId.source.sourceSystem.id,
cityId = bookingData.cityId.id,
diff --git a/server/src/test/scala/com/lbs/server/actor/AuthSpec.scala b/server/src/test/scala/com/lbs/server/actor/AuthSpec.scala
index 1f3b2a8..acd754b 100644
--- a/server/src/test/scala/com/lbs/server/actor/AuthSpec.scala
+++ b/server/src/test/scala/com/lbs/server/actor/AuthSpec.scala
@@ -13,7 +13,7 @@ class AuthSpec extends AkkaTestKit {
"An Auth actor " when {
val source = MessageSource(TelegramMessageSourceSystem, "1")
- val userId = UserId(1L, source)
+ val userId = UserId(1L, 1L, source)
"user is unauthorized" must {
val unauthorizedHelpActor = TestProbe()
@@ -23,7 +23,7 @@ class AuthSpec extends AkkaTestKit {
val loginActorFactory: ByMessageSourceWithOriginatorActorFactory = (_, _) => loginActor.ref
val chatActorFactory: UserId => ActorRef = _ => chatActor.ref
val dataService = mock(classOf[DataService])
- when(dataService.findUserIdBySource(source)).thenReturn(None)
+ when(dataService.findUserAndAccountIdBySource(source)).thenReturn(None)
val auth = system.actorOf(Auth.props(source, dataService, unauthorizedHelpFactory, loginActorFactory, chatActorFactory))
@@ -57,7 +57,7 @@ class AuthSpec extends AkkaTestKit {
"forward initial message to chat actor after the user has logged in" in {
val cmd = Command(source, Message("1", Some("any")))
- val msg = LoggedIn(ForwardCommand(cmd), 1L)
+ val msg = LoggedIn(ForwardCommand(cmd), 1L, 1L)
auth ! msg
chatActor.expectMsg(cmd)
}
@@ -79,7 +79,7 @@ class AuthSpec extends AkkaTestKit {
val loginActorFactory: ByMessageSourceWithOriginatorActorFactory = (_, _) => loginActor.ref
val chatActorFactory: UserId => ActorRef = _ => chatActor.ref
val dataService = mock(classOf[DataService])
- when(dataService.findUserIdBySource(source)).thenReturn(Some(userId.userId))
+ when(dataService.findUserAndAccountIdBySource(source)).thenReturn(Some(userId.userId, userId.accountId))
val auth = system.actorOf(Auth.props(source, dataService, unauthorizedHelpFactory, loginActorFactory, chatActorFactory))