diff --git a/README.md b/README.md index 767ca9a..30adc4e 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,69 @@ ## How to launch +First of all, you need to launch PostgreSQL and Redis: + ```bash docker compose start -``` +``` + +Then, start the REST-api: ```bash -sbt "project stub" run +sbt "project service" run +``` + +And finally, run the telegram bot: + +```bash +sbt "project bot" run +``` + +## Internals + +### Actual database schema + +```postgresql +create table offers +( + id uuid primary key, + name text not null, + price integer not null, + description text not null, + status text not null +); + +create table users +( + id uuid primary key, + name text not null, + login text not null unique, + status text not null, + password_hash text not null, + password_salt text not null +); + +create table user_offers +( + offer_id uuid primary key, + user_id uuid not null references users(id) +); ``` + +### Authorization + +Each user has login (telegram @login) and password, and, in order to use the service, he should get a session and then attach it to each request + +Creating a session: + +create-session + +Use session in some request: + +use-session + +### Telegram-bot + +State machine diagram: + +bot-state-machine diff --git a/docs/bot-state-machine.png b/docs/bot-state-machine.png new file mode 100644 index 0000000..78c1061 Binary files /dev/null and b/docs/bot-state-machine.png differ diff --git a/docs/create-session.png b/docs/create-session.png new file mode 100644 index 0000000..f68b4b0 Binary files /dev/null and b/docs/create-session.png differ diff --git a/docs/use-session.png b/docs/use-session.png new file mode 100644 index 0000000..144968a Binary files /dev/null and b/docs/use-session.png differ diff --git a/service/src/main/scala/com/github/mmvpm/service/api/AuthHandler.scala b/service/src/main/scala/com/github/mmvpm/service/api/AuthHandler.scala index 755a804..ff1b1ef 100644 --- a/service/src/main/scala/com/github/mmvpm/service/api/AuthHandler.scala +++ b/service/src/main/scala/com/github/mmvpm/service/api/AuthHandler.scala @@ -20,7 +20,7 @@ class AuthHandler[F[_]: Monad](override val authService: AuthService[F], userSer private val signUp: ServerEndpoint[Any, F] = endpoint.withApiErrors.post - .summary("Зарегистрировать нового пользователя") + .summary("Register a new user") .in("api" / "v1" / "auth" / "sign-up") .in(jsonBody[SignUpRequest]) .out(jsonBody[UserResponse]) @@ -28,14 +28,14 @@ class AuthHandler[F[_]: Monad](override val authService: AuthService[F], userSer private val signIn: ServerEndpoint[Any, F] = endpoint.withApiErrors.withLoginPassword.post - .summary("Обменять логин и пароль на сессию") + .summary("Get session by login and password") .in("api" / "v1" / "auth" / "sign-in") .out(jsonBody[SessionResponse]) .serverLogic(userId => _ => authService.getSession(userId).value) private val whoAmI: ServerEndpoint[Any, F] = endpoint.withApiErrors.get - .summary("Получить ID пользователя по сессии") + .summary("Get user ID by their session") .in("api" / "v1" / "auth" / "whoami" / path[Session]("session")) .out(jsonBody[UserIdResponse]) .serverLogic(authService.whoami(_).value) diff --git a/service/src/main/scala/com/github/mmvpm/service/api/OfferHandler.scala b/service/src/main/scala/com/github/mmvpm/service/api/OfferHandler.scala index a417003..c4ec304 100644 --- a/service/src/main/scala/com/github/mmvpm/service/api/OfferHandler.scala +++ b/service/src/main/scala/com/github/mmvpm/service/api/OfferHandler.scala @@ -20,21 +20,21 @@ class OfferHandler[F[_]: Applicative](offerService: OfferService[F], override va private val getOffer: ServerEndpoint[Any, F] = endpoint.withApiErrors.get - .summary("Получить объявление по его id") + .summary("Get the offer by its ID") .in("api" / "v1" / "offer" / path[OfferID]("offer-id")) .out(jsonBody[OfferResponse]) .serverLogic(offerService.getOffer(_).value) private val getOffers: ServerEndpoint[Any, F] = endpoint.withApiErrors.get - .summary("Получить все объявления данного пользователя") + .summary("Get all offers of the specified user") .in("api" / "v1" / "offer" / "user" / path[UserID]("user-id")) .out(jsonBody[OffersResponse]) .serverLogic(offerService.getOffers(_).value) private val createOffer: ServerEndpoint[Any, F] = endpoint.withApiErrors.withSession.post - .summary("Создать объявление") + .summary("Create an offer") .in("api" / "v1" / "offer") .in(jsonBody[CreateOfferRequest]) .out(jsonBody[OfferResponse]) @@ -42,7 +42,7 @@ class OfferHandler[F[_]: Applicative](offerService: OfferService[F], override va private val updateOffer: ServerEndpoint[Any, F] = endpoint.withApiErrors.withSession.put - .summary("Изменить объявление") + .summary("Update the offer") .in("api" / "v1" / "offer" / path[OfferID]("offer-id")) .in(jsonBody[UpdateOfferRequest]) .out(jsonBody[OfferResponse]) @@ -52,7 +52,7 @@ class OfferHandler[F[_]: Applicative](offerService: OfferService[F], override va private val deleteOffer: ServerEndpoint[Any, F] = endpoint.withApiErrors.withSession.delete - .summary("Удалить объявление") + .summary("Delete the offer") .in("api" / "v1" / "offer" / path[OfferID]("offer-id")) .out(jsonBody[OkResponse]) .serverLogic(userId => offerId => offerService.deleteOffer(userId, offerId).value) diff --git a/service/src/main/scala/com/github/mmvpm/service/api/UserHandler.scala b/service/src/main/scala/com/github/mmvpm/service/api/UserHandler.scala index 98c1cae..a324c43 100644 --- a/service/src/main/scala/com/github/mmvpm/service/api/UserHandler.scala +++ b/service/src/main/scala/com/github/mmvpm/service/api/UserHandler.scala @@ -19,14 +19,14 @@ class UserHandler[F[_]: Functor](userService: UserService[F], override val authS private val getUser: ServerEndpoint[Any, F] = endpoint.withApiErrors.get - .summary("Получить пользователя по его id") + .summary("Get the user by their ID") .in("api" / "v1" / "user" / path[UserID]("user-id")) .out(jsonBody[UserResponse]) .serverLogic(userService.getUser(_).value) private val deleteUser: ServerEndpoint[Any, F] = endpoint.withApiErrors.withSession.delete - .summary("Удалить свой профиль") + .summary("Delete own profile") .in("api" / "v1" / "user") .out(jsonBody[OkResponse]) .serverLogic(userId => _ => userService.deleteUser(userId).value) diff --git a/service/src/main/scala/com/github/mmvpm/service/api/util/SchemaInstances.scala b/service/src/main/scala/com/github/mmvpm/service/api/util/SchemaInstances.scala index 56956b5..c1564b0 100644 --- a/service/src/main/scala/com/github/mmvpm/service/api/util/SchemaInstances.scala +++ b/service/src/main/scala/com/github/mmvpm/service/api/util/SchemaInstances.scala @@ -12,48 +12,48 @@ object SchemaInstances { // model implicit val schemaOfferStatus: Schema[OfferStatus] = - Schema.derivedEnumerationValue.description("Статус объявления") + Schema.derivedEnumerationValue.description("Offer status") implicit val schemaOfferDescription: Schema[OfferDescription] = - Schema.derived.description("Задаваемые пользователем поля объявления") + Schema.derived.description("User-defined offer fields") implicit val schemaOffer: Schema[Offer] = - Schema.derived.description("Объявление") + Schema.derived.description("Offer") implicit val schemaUserStatus: Schema[UserStatus] = - Schema.derivedEnumerationValue.description("Статус пользователя") + Schema.derivedEnumerationValue.description("User status") implicit val schemaUser: Schema[User] = - Schema.derived.description("Пользователь") + Schema.derived.description("User") // requests implicit val schemaSignUpRequest: Schema[SignUpRequest] = - Schema.derived.description("Запрос на регистрацию пользователя") + Schema.derived.description("Request to register a new user") implicit val schemaUpdateOfferRequest: Schema[UpdateOfferRequest] = - Schema.derived.description("Запрос на изменение объявления") + Schema.derived.description("Request to update the offer") implicit val schemaCreateOfferRequest: Schema[CreateOfferRequest] = - Schema.derived.description("Запрос на создание объявления") + Schema.derived.description("Request to create an offer") // responses implicit val schemaOkResponse: Schema[OkResponse] = - Schema.derived.description("Успех") + Schema.derived.description("Success") implicit val schemaSessionResponse: Schema[SessionResponse] = - Schema.derived.description("Сессия пользователя") + Schema.derived.description("User session") implicit val schemaUserResponse: Schema[UserResponse] = - Schema.derived.description("Пользователь") + Schema.derived.description("User") implicit val schemaUserIdResponse: Schema[UserIdResponse] = - Schema.derived.description("ID пользователя") + Schema.derived.description("User ID") implicit val schemaOfferResponse: Schema[OfferResponse] = - Schema.derived.description("Объявление") + Schema.derived.description("Offer") implicit val schemaOffersResponse: Schema[OffersResponse] = - Schema.derived.description("Список объявлений") + Schema.derived.description("List of offers") }