Skip to content

Commit 37d2353

Browse files
committed
Forbid invalid inputs (#55)
1 parent 97c4498 commit 37d2353

File tree

4 files changed

+61
-22
lines changed

4 files changed

+61
-22
lines changed

bot/src/main/scala/com/github/mmvpm/bot/state/State.scala

+13-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.github.mmvpm.bot.state
22

33
import com.github.mmvpm.bot.model.{Button, Draft, Tag, TgPhoto}
4+
import com.github.mmvpm.bot.util.PriceUtils.priceText
45
import com.github.mmvpm.model.{Offer, OfferID}
56

67
import scala.util.matching.Regex
@@ -158,11 +159,14 @@ object State {
158159
s"""
159160
|$summary
160161
|
161-
|С помощью кнопок от 1 до $StepSizeCropped можно выбрать одно объявление, чтобы посмотреть его подробнее
162+
|С помощью $buttonRangeText можно выбрать одно объявление, чтобы посмотреть его подробнее
162163
|""".stripMargin
163164
else
164165
"По вашему запросу ничего не нашлось :("
165166

167+
private lazy val buttonRangeText =
168+
if (StepSizeCropped == 1) "кнопки 1" else s"кнопок от 1 до $StepSizeCropped"
169+
166170
val photos: Seq[TgPhoto] =
167171
offers
168172
.slice(from, from + StepSizeCropped)
@@ -185,7 +189,7 @@ object State {
185189
.slice(from, from + StepSizeCropped)
186190
.zipWithIndex
187191
.map { case (offer, idx) =>
188-
s"${idx + 1}. ${offer.description.name} (${offer.description.price} рублей)"
192+
s"${idx + 1}. ${offer.description.name} (${priceText(offer.description.price)})"
189193
}
190194
.mkString("\n\n")
191195
}
@@ -208,7 +212,7 @@ object State {
208212
s"""
209213
|${offer.description.name}
210214
|
211-
|Цена: ${offer.description.price} рублей
215+
|Цена: ${priceText(offer.description.price)}
212216
|
213217
|${offer.description.text}
214218
|
@@ -270,11 +274,14 @@ object State {
270274
|
271275
|$summary
272276
|
273-
|С помощью кнопок от 1 до $StepSizeCropped можно выбрать одно объявление, чтобы посмотреть его подробнее
277+
|С помощью $buttonRangeText можно выбрать одно объявление, чтобы посмотреть его подробнее
274278
|""".stripMargin
275279
else
276280
"У вас пока что нет ни одного объявления"
277281

282+
private lazy val buttonRangeText =
283+
if (StepSizeCropped == 1) "кнопки 1" else s"кнопок от 1 до $StepSizeCropped"
284+
278285
val photos: Seq[TgPhoto] =
279286
offers
280287
.take(StepSizeCropped)
@@ -291,7 +298,7 @@ object State {
291298
.take(StepSizeCropped)
292299
.zipWithIndex
293300
.map { case (offer, idx) =>
294-
s"${idx + 1}. ${offer.description.name} (${offer.description.price} рублей)"
301+
s"${idx + 1}. ${offer.description.name} (${priceText(offer.description.price)})"
295302
}
296303
.mkString("\n\n")
297304
}
@@ -312,7 +319,7 @@ object State {
312319
s"""
313320
|${offer.description.name}
314321
|
315-
|Цена: ${offer.description.price} рублей
322+
|Цена: ${priceText(offer.description.price)}
316323
|
317324
|${offer.description.text}
318325
|

bot/src/main/scala/com/github/mmvpm/bot/state/StateManagerImpl.scala

+29-16
Original file line numberDiff line numberDiff line change
@@ -83,35 +83,48 @@ class StateManagerImpl[F[_]: MonadCancelThrow](ofsManager: OfsManager[F]) extend
8383
private def toCreateOfferName(current: State)(implicit message: Message): F[State] =
8484
CreateOfferName(current).pure
8585

86-
private def toCreateOfferPrice(current: State)(implicit message: Message): F[State] =
87-
message.text match {
88-
case Some(name) => CreateOfferPrice(current, Draft(name = Some(name))).pure
89-
case _ => Error(current, "Пожалуйста, введите название объявления").pure
90-
}
86+
private def toCreateOfferPrice(current: State)(implicit message: Message): F[State] = {
87+
val newState = for {
88+
name <- message.text
89+
if name.containsAtLeastOneLetterOrDigit
90+
} yield CreateOfferPrice(current, Draft(name = Some(name)))
91+
92+
newState
93+
.getOrElse(
94+
Error(current, "Пожалуйста, введите название объявления (должно содержать хотя бы одну букву)")
95+
)
96+
.pure
97+
}
9198

9299
private def toCreateOfferDescription(current: State)(implicit message: Message): F[State] = {
93100
val newState = for {
94101
priceRaw <- message.text
95102
price <- priceRaw.toIntOption
103+
if price >= 0
96104
draft <- current match {
97105
case CreateOfferPrice(_, draft) => Some(draft)
98106
case _ => None
99107
}
100108
updatedDraft = draft.copy(price = Some(price))
101109
} yield CreateOfferDescription(current, updatedDraft)
102110

103-
newState.getOrElse(Error(current, "Пожалуйста, введите цену (целое число рублей)")).pure
111+
newState.getOrElse(Error(current, "Пожалуйста, введите цену (целое число рублей от 0 до 2 млрд)")).pure
104112
}
105113

106114
private def toCreateOfferPhoto(current: State)(implicit message: Message): F[State] =
107115
current match {
108116
case CreateOfferDescription(_, draft) => // description has been uploaded
109117
val newState = for {
110118
description <- message.text
119+
if description.containsAtLeastOneLetterOrDigit
111120
updatedDraft = draft.copy(description = Some(description))
112121
} yield CreateOfferPhoto(current, updatedDraft)
113122

114-
newState.getOrElse(Error(current, "Пожалуйста, введите описание к объявлению")).pure
123+
newState
124+
.getOrElse(
125+
Error(current, "Пожалуйста, введите описание к объявлению (должно содержать хотя бы одну букву)")
126+
)
127+
.pure
115128

116129
case CreateOfferPhoto(_, draft) => // another photo has been uploaded
117130
val newState = for {
@@ -213,41 +226,41 @@ class StateManagerImpl[F[_]: MonadCancelThrow](ofsManager: OfsManager[F]) extend
213226
current match {
214227
case EditOfferName(_, offerId) =>
215228
message.text match {
216-
case Some(newName) =>
229+
case Some(newName) if newName.containsAtLeastOneLetterOrDigit =>
217230
ofsManager
218231
.updateOffer(offerId, OfferPatch(name = Some(newName)))
219232
.handleDefaultErrors(
220233
current,
221234
ifSuccess = _ => UpdatedOffer(current, s"Название было изменено на \"$newName\"").pure
222235
)
223-
case None =>
224-
Error(current, "Пожалуйста, введите новое название объявления").pure
236+
case _ =>
237+
Error(current, "Пожалуйста, введите новое название объявления (должно содержать хотя бы одну букву)").pure
225238
}
226239

227240
case EditOfferPrice(_, offerId) =>
228-
message.text.flatMap(_.toIntOption) match {
241+
message.text.flatMap(_.toIntOption).filter(_ >= 0) match {
229242
case Some(newPrice) =>
230243
ofsManager
231244
.updateOffer(offerId, OfferPatch(price = Some(newPrice)))
232245
.handleDefaultErrors(
233246
current,
234247
ifSuccess = _ => UpdatedOffer(current, s"Цена была изменена на $newPrice").pure
235248
)
236-
case None =>
237-
Error(current, "Пожалуйста, введите новую цену (целое число рублей)").pure
249+
case _ =>
250+
Error(current, "Пожалуйста, введите новую цену (целое число рублей от 0 до 2 млрд)").pure
238251
}
239252

240253
case EditOfferDescription(_, offerId) =>
241254
message.text match {
242-
case Some(newDescription) =>
255+
case Some(newDescription) if newDescription.containsAtLeastOneLetterOrDigit =>
243256
ofsManager
244257
.updateOffer(offerId, OfferPatch(description = Some(newDescription)))
245258
.handleDefaultErrors(
246259
current,
247260
ifSuccess = _ => UpdatedOffer(current, s"Описание было изменено").pure
248261
)
249-
case None =>
250-
Error(current, "Пожалуйста, введите новое описание объявления").pure
262+
case _ =>
263+
Error(current, "Пожалуйста, введите новое описание объявления (должно содержать хотя бы одну букву)").pure
251264
}
252265

253266
case AddOfferPhoto(_, offerId) =>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.github.mmvpm.bot.util
2+
3+
object PriceUtils {
4+
5+
def priceText(price: Int): String =
6+
price match {
7+
case 0 => "Бесплатно"
8+
case _ =>
9+
val suffix = price % 10 match {
10+
case 1 => "рубль"
11+
case 2 | 3 | 4 => "рубля"
12+
case _ => "рублей"
13+
}
14+
s"$price $suffix"
15+
}
16+
}

bot/src/main/scala/com/github/mmvpm/bot/util/StringUtils.scala

+3
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,8 @@ object StringUtils {
1212

1313
def toUUID: UUID =
1414
UUID.fromString(string)
15+
16+
def containsAtLeastOneLetterOrDigit: Boolean =
17+
string.filter(_ != '\u3164').exists(_.isLetterOrDigit)
1518
}
1619
}

0 commit comments

Comments
 (0)