diff --git a/build.sbt b/build.sbt index 2350a09..ee855e4 100644 --- a/build.sbt +++ b/build.sbt @@ -4,4 +4,16 @@ version := "0.1" scalaVersion := "2.12.9" -libraryDependencies += "com.bot4s" %% "telegram-core" % "4.4.0-RC2" \ No newline at end of file +libraryDependencies ++= Seq( + "com.bot4s" %% "telegram-core" % "4.4.0-RC2", + "com.softwaremill.sttp" %% "json4s" % "1.7.2", + "org.json4s" %% "json4s-native" % "3.6.0" +) + +libraryDependencies ++= Seq( + "com.typesafe.slick" %% "slick" % "3.3.1", + "org.slf4j" % "slf4j-nop" % "1.7.26", + "com.typesafe.slick" %% "slick-hikaricp" % "3.3.1" +) + +libraryDependencies += "com.h2database" % "h2" % "1.4.200" \ No newline at end of file diff --git a/src/main/resourses/reference.conf b/src/main/resourses/reference.conf new file mode 100644 index 0000000..1601bc7 --- /dev/null +++ b/src/main/resourses/reference.conf @@ -0,0 +1,6 @@ +h2mem1 = { + url = "jdbc:h2:mem:test1" + driver = org.h2.Driver + connectionPool = disabled + keepAliveConnection = true +} \ No newline at end of file diff --git a/src/main/scala/bot/BotStarter.scala b/src/main/scala/bot/BotStarter.scala index 565a9a9..ec545a0 100644 --- a/src/main/scala/bot/BotStarter.scala +++ b/src/main/scala/bot/BotStarter.scala @@ -7,7 +7,8 @@ import com.bot4s.telegram.api.declarative.Commands import com.bot4s.telegram.clients.{FutureSttpClient, ScalajHttpClient} import com.bot4s.telegram.future.{Polling, TelegramBot} import com.bot4s.telegram.models.{Message, User} -import com.softwaremill.sttp.SttpBackendOptions +import com.softwaremill.sttp.{SttpBackendOptions, sttp} +import com.softwaremill.sttp.json4s.asJson import com.softwaremill.sttp.okhttp.{OkHttpBackend, OkHttpFutureBackend} import slogging.{LogLevel, LoggerConfig, PrintLoggerFactory} @@ -17,43 +18,89 @@ import scala.collection.mutable.Queue import scala.concurrent.duration.Duration import scala.concurrent.{Await, ExecutionContext, Future} import scala.io.Source +import scala.util.Random +import scala.io.Source +import com.softwaremill.sttp._ +import com.softwaremill.sttp.json4s._ +import org.json4s.native.Serialization +import slick.lifted.TableQuery -class BotStarter(override val client: RequestHandler[Future]) extends TelegramBot +class BotStarter(override val client: RequestHandler[Future], val service: Service, + val userHandler: DBUserHandler, val messageHandler: DBMessageHandler) extends TelegramBot with Polling with Commands[Future] { - val registeredUsers: mutable.Set[User] = mutable.Set[User]() - onCommand("/start") { implicit msg => msg.from match { case None => reply("Register error").void - case Some(user) => { - registeredUsers += user - reply(s"You're registered.\n Your id is ${user.id}").void - } + case Some(user) => + userHandler.register(user).flatMap(_ => + reply(s"You're registered.\nYour id is ${user.id}").void) } } onCommand("/users") { implicit msg => - var usersString = "" - registeredUsers.foreach { - it => usersString += s"${it.firstName} ${it.lastName}\n" + userHandler.show.flatMap(reply(_).void) + } + + onCommand("/check") { implicit msg => + msg.from match { + case None => reply("Error.").void + case Some(user) => + messageHandler.show(user.id.toString).flatMap(messages => + messageHandler.clear(user.id.toString).flatMap(_ => + reply(messages).void) + ) + } + } + + onCommand("/send") { implicit msg => + var from_id: Int = 0 + msg.from match { + case None => from_id = 0 + case Some(user) => from_id = user.id + } + + msg.text match { + case None => reply("Enter non-empty message").void + case Some(s) => + val id: String = s.slice(6, 15) + val text: String = s.slice(16, s.length) + messageHandler.send(from_id.toString, id, text) + reply(s"Message was sent to $id").void } - reply(usersString).void + } + + onCommand("/cat") { implicit msg => + service.getCat.flatMap(reply(_)).void } } object BotStarter { def main(args: Array[String]): Unit = { implicit val ec: ExecutionContext = ExecutionContext.global - implicit val backend = OkHttpFutureBackend( + implicit val backend: SttpBackend[Future, Nothing] = OkHttpFutureBackend( SttpBackendOptions.Default.socksProxy("ps8yglk.ddns.net", 11999) ) + val users = TableQuery[Users] + val messages = TableQuery[Messages] + val userHandler = new DBUserHandler(users, messages) + val messageHandler = new DBMessageHandler(users, messages) + + val service: Service = new Service() + val fileSource = Source.fromFile("token.txt") val token = fileSource.mkString fileSource.close() - val bot = new BotStarter(new FutureSttpClient(token)) - Await.result(bot.run(), Duration.Inf) + + val init = for { + _ <- userHandler.init() + _ <- messageHandler.init() + bot = new BotStarter(new FutureSttpClient(token), service, + userHandler, messageHandler) + _ <- bot.run() + } yield () + Await.result(init, Duration.Inf) } } \ No newline at end of file diff --git a/src/main/scala/bot/DBMessageHandler.scala b/src/main/scala/bot/DBMessageHandler.scala new file mode 100644 index 0000000..da850fb --- /dev/null +++ b/src/main/scala/bot/DBMessageHandler.scala @@ -0,0 +1,45 @@ +package bot + +import scala.concurrent.{Await, Future} +import slick.jdbc.H2Profile.api._ + +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration.Duration + +class Messages(tag: Tag) extends Table[(Int, String, Int, Int)](tag, "Messages"){ + def id = column[Int]("Id", O.PrimaryKey) + def message = column[String]("Message") + def senderId = column[Int]("SenderId") + def receiverId = column[Int]("ReceiverId") + def * = (id, message, senderId, receiverId) +} + +class DBMessageHandler(users: TableQuery[Users], messages: TableQuery[Messages]) { + lazy val database = Database.forConfig("h2mem1") + var messageId = 0 + + def init(): Future[Unit] = { + database.run(messages.schema.createIfNotExists) + } + + def send(senderId: String, receiverId: String, message: String): Future[Unit] = { + val req = for { + _ <- messages += (messageId, message, senderId.toInt, receiverId.toInt) + } yield() + messageId += 1 + database.run(req) + } + + def show(id: String): Future[String] = { + val req = for { + idMessages <- messages.filter(it => it.receiverId === id.toInt).result + } yield idMessages + database.run(req).flatMap(seq => Future ( + seq.map(it => s"From ${it._3}\n${it._2}\n").mkString("\n")) + ) + } + + def clear(id: String): Future[Unit] = { + database.run(messages.filter(it => it.receiverId === id.toInt).delete).flatMap(_ => Future()) + } +} diff --git a/src/main/scala/bot/DBUserHandler.scala b/src/main/scala/bot/DBUserHandler.scala new file mode 100644 index 0000000..bda9f2d --- /dev/null +++ b/src/main/scala/bot/DBUserHandler.scala @@ -0,0 +1,38 @@ +package bot + +import scala.concurrent.{Await, Future} +import slick.jdbc.H2Profile.api._ +import com.bot4s.telegram.models.User +import slick.jdbc.H2Profile + +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent.duration.Duration + +class Users(tag: Tag) extends Table[(Int, String, String)](tag, "Messages"){ + def id = column[Int]("Id", O.PrimaryKey) + def name = column[String]("Name") + def username = column[String]("Username") + def * = (id, name, username) +} + +class DBUserHandler(users: TableQuery[Users], messages: TableQuery[Messages]) { + lazy val database = Database.forConfig("h2mem1") + + def init(): Future[Unit] = { + database.run(users.schema.createIfNotExists) + } + + def register(user: User): Future[Unit] = { + val req = for { + _ <- users += (user.id, user.firstName + " " + user.lastName.getOrElse(""), user.username.getOrElse("")) + } yield () + database.run(req) + } + + def show: Future[String] = { + val req = for { + allUsers <- users.result + } yield allUsers + database.run(req).flatMap(seq => Future(seq.map(it => s"${it._2}, id: ${it._1}").mkString("\n"))) + } +} diff --git a/src/main/scala/bot/MessageHandler.scala b/src/main/scala/bot/MessageHandler.scala new file mode 100644 index 0000000..66bb0ef --- /dev/null +++ b/src/main/scala/bot/MessageHandler.scala @@ -0,0 +1,21 @@ +package bot + +import scala.collection.mutable + +class MessageHandler { + var messagesUsers: mutable.Map[String, mutable.ListBuffer[(String, String)]] = + mutable.Map[String, mutable.ListBuffer[(String, String)]]().withDefaultValue(mutable.ListBuffer()) + + def send(senderId: String, recieverId: String, message: String): Unit = { + if (!messagesUsers.contains(recieverId)) { + messagesUsers(recieverId) = mutable.ListBuffer() + } + messagesUsers(recieverId) += Tuple2(senderId, message) + } + + def show(id: String): String = messagesUsers(id).foldLeft(""){ + (last, p) => last + s"From: ${p._1}\n${p._2}\n\n" + } + + def clear(id: String): Unit = messagesUsers(id).clear() +} diff --git a/src/main/scala/bot/Service.scala b/src/main/scala/bot/Service.scala new file mode 100644 index 0000000..dd71658 --- /dev/null +++ b/src/main/scala/bot/Service.scala @@ -0,0 +1,24 @@ +package bot + +import com.softwaremill.sttp.{SttpBackendOptions, sttp} +import com.softwaremill.sttp.json4s.asJson + +import scala.concurrent.{Await, ExecutionContext, Future} +import com.softwaremill.sttp._ +import org.json4s.native.Serialization + +case class Response(data: List[Data]) +case class Data(link: String) + +class Service(implicit val backend: SttpBackend[Future, Nothing], + implicit val serialization : Serialization.type = org.json4s.native.Serialization, + implicit val ec: ExecutionContext = ExecutionContext.global) { + val request: RequestT[Id, Response, Nothing] = sttp + .header("Authorization", "Client-ID 2a47c24862afdf7") + .get(uri"https://api.imgur.com/3/gallery/search?q=cats") + .response(asJson[Response]) + + def getCat: Future[String] = backend.send(request).map { response => + scala.util.Random.shuffle(response.unsafeBody.data).head.link + } +} \ No newline at end of file diff --git a/src/main/scala/bot/UserHandler.scala b/src/main/scala/bot/UserHandler.scala new file mode 100644 index 0000000..96fb193 --- /dev/null +++ b/src/main/scala/bot/UserHandler.scala @@ -0,0 +1,16 @@ +package bot + +import com.bot4s.telegram.models.User + +import scala.collection.mutable + +class UserHandler { + + val registeredUsers: mutable.Set[User] = mutable.Set[User]() + + def register(user: User): Unit = registeredUsers += user + + def show(): String = registeredUsers.foldLeft("") { + (last, user) => last + s"${user.firstName} ${user.lastName.getOrElse("")}, id: ${user.id}\n" + } +}