Skip to content

Commit d21f42c

Browse files
authored
fix/qg-270: исправлено сохранение черновиков клиента и записи журнала в случае ошибки отправки формы (#271)
2 parents c9df19d + bcb4812 commit d21f42c

32 files changed

Lines changed: 296 additions & 248 deletions

app/build.gradle.kts

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,9 @@ kover {
121121
currentProject {
122122
createVariant("Endpoints") {
123123
add("jvm")
124-
124+
}
125+
createVariant("Ops") {
126+
add("jvm")
125127
}
126128
}
127129
reports {
@@ -163,7 +165,59 @@ kover {
163165
groupBy = kotlinx.kover.gradle.plugin.dsl.GroupingEntityType.CLASS
164166

165167
bound {
166-
minValue = 100
168+
minValue = 90
169+
coverageUnits.set(CoverageUnit.INSTRUCTION)
170+
aggregationForGroup.set(AggregationType.COVERED_PERCENTAGE)
171+
}
172+
}
173+
}
174+
}
175+
176+
variant("Ops") {
177+
178+
html {
179+
onCheck = true
180+
}
181+
filters {
182+
includes {
183+
classes("pro.qyoga.**Op")
184+
}
185+
}
186+
187+
verify {
188+
onCheck = true
189+
rule("Endpoints coverage") {
190+
disabled = false
191+
groupBy = kotlinx.kover.gradle.plugin.dsl.GroupingEntityType.CLASS
192+
193+
bound {
194+
minValue = 90
195+
coverageUnits.set(CoverageUnit.INSTRUCTION)
196+
aggregationForGroup.set(AggregationType.COVERED_PERCENTAGE)
197+
}
198+
}
199+
}
200+
}
201+
202+
variant("Ops") {
203+
204+
html {
205+
onCheck = true
206+
}
207+
filters {
208+
includes {
209+
classes("pro.qyoga.**Op")
210+
}
211+
}
212+
213+
verify {
214+
onCheck = true
215+
rule("Endpoints coverage") {
216+
disabled = false
217+
groupBy = kotlinx.kover.gradle.plugin.dsl.GroupingEntityType.CLASS
218+
219+
bound {
220+
minValue = 87
167221
coverageUnits.set(CoverageUnit.INSTRUCTION)
168222
aggregationForGroup.set(AggregationType.COVERED_PERCENTAGE)
169223
}

app/src/main/kotlin/pro/azhidkov/platform/spring/http/ResponseEntityExt.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ package pro.azhidkov.platform.spring.http
33
import org.springframework.http.ResponseEntity
44

55

6-
fun hxRedirect(path: String): ResponseEntity<Unit> {
6+
fun hxRedirect(path: String, vararg headers: Pair<String, String>): ResponseEntity<Unit> {
77
return ResponseEntity.ok()
88
.header("HX-Redirect", path)
9+
.headers { headers.forEach { (key, value) -> it.add(key, value) } }
910
.build()
1011
}
1112

app/src/main/kotlin/pro/azhidkov/platform/spring/mvc/ModelAndViewExt.kt

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,7 @@
11
package pro.azhidkov.platform.spring.mvc
22

3-
import org.springframework.ui.ModelMap
43
import org.springframework.web.servlet.ModelAndView
54

6-
@Deprecated("Передавайте Map<String, Any?> явно")
7-
class ModelBuilder(
8-
private val modelMap: ModelMap
9-
) {
10-
11-
infix fun String.bindTo(value: Any?) {
12-
modelMap.addAttribute(this, value)
13-
}
14-
15-
}
16-
17-
@Deprecated("Передавайте Map<String, Any?> явно")
18-
fun modelAndView(viewName: String, buildModel: ModelBuilder.() -> Unit = {}): ModelAndView {
19-
val modelAndView = ModelAndView(viewName)
20-
val builder = ModelBuilder(modelAndView.modelMap)
21-
builder.buildModel()
22-
return modelAndView
23-
}
24-
255
fun modelAndView(viewName: String, model: Map<String, Any?>): ModelAndView {
266
val modelAndView = ModelAndView(viewName)
277
modelAndView.modelMap.mergeAttributes(model)

app/src/main/kotlin/pro/qyoga/app/therapist/clients/ClientPageModel.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ data class ClientPageModel<T : ClientPageFragmentModel>(
2424
val fragmentModel: T
2525
) : ModelAndView(
2626
viewId("therapist/clients/client-edit"), mapOf(
27-
"client" to client.toDto(),
28-
"activeTab" to activeTab,
27+
"client" to client.toDto(),
28+
"activeTab" to activeTab,
2929
) + fragmentModel.model
30-
)
30+
)

app/src/main/kotlin/pro/qyoga/app/therapist/clients/cards/CreateClientCardPageController.kt

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ import org.springframework.ui.Model
66
import org.springframework.web.bind.annotation.GetMapping
77
import org.springframework.web.bind.annotation.PostMapping
88
import org.springframework.web.bind.annotation.RequestMapping
9-
import org.springframework.web.servlet.ModelAndView
10-
import pro.azhidkov.platform.kotlin.mapSuccess
11-
import pro.azhidkov.platform.kotlin.recoverFailure
9+
import pro.azhidkov.platform.kotlin.value
10+
import pro.azhidkov.platform.spring.http.hxRedirect
11+
import pro.qyoga.app.platform.notFound
1212
import pro.qyoga.core.clients.cards.Client
1313
import pro.qyoga.core.clients.cards.ClientsRepo
1414
import pro.qyoga.core.clients.cards.dtos.ClientCardDto
1515
import pro.qyoga.core.clients.cards.errors.DuplicatedPhoneException
16+
import pro.qyoga.core.clients.cards.model.Client
1617
import pro.qyoga.core.users.auth.dtos.QyogaUserDetails
1718

1819

@@ -24,29 +25,30 @@ class CreateClientCardPageController(
2425

2526
@GetMapping("/create")
2627
fun getCreateClientPage(model: Model): String {
27-
model.addAttribute("formAction", "/therapist/clients/create")
28+
model.addAttribute("formAction", FORM_ACTION)
2829
return "therapist/clients/client-create"
2930
}
3031

3132
@PostMapping("/create")
3233
fun createClient(
3334
clientCardDto: ClientCardDto,
3435
@AuthenticationPrincipal principal: QyogaUserDetails,
35-
): ModelAndView {
36+
): Any {
3637
val res = runCatching {
3738
clientsRepo.save(Client(principal.id, clientCardDto))
3839
}
3940

40-
val modelAndView = res
41-
.mapSuccess {
42-
ModelAndView("redirect:/therapist/clients")
43-
}
44-
.recoverFailure { _: DuplicatedPhoneException ->
45-
editClientFormWithValidationError(clientCardDto)
46-
}
47-
.getOrThrow()
41+
return when (res.value()) {
42+
is Client -> hxRedirect("/therapist/clients", "HX-Trigger" to "formSaved")
4843

49-
return modelAndView
44+
null -> notFound
45+
is DuplicatedPhoneException -> editClientFormWithValidationError(FORM_ACTION, clientCardDto)
46+
else -> throw res.exceptionOrNull()!!
47+
}
48+
}
49+
50+
companion object {
51+
private const val FORM_ACTION = "/therapist/clients/create"
5052
}
5153

5254
}

app/src/main/kotlin/pro/qyoga/app/therapist/clients/cards/EditClientCardPageController.kt

Lines changed: 14 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,22 @@ package pro.qyoga.app.therapist.clients.cards
22

33
import org.springframework.data.repository.findByIdOrNull
44
import org.springframework.stereotype.Controller
5-
import org.springframework.ui.ModelMap
65
import org.springframework.web.bind.annotation.GetMapping
76
import org.springframework.web.bind.annotation.PathVariable
87
import org.springframework.web.bind.annotation.PostMapping
98
import org.springframework.web.servlet.ModelAndView
10-
import pro.azhidkov.platform.kotlin.mapNull
11-
import pro.azhidkov.platform.kotlin.mapSuccessOrNull
12-
import pro.azhidkov.platform.kotlin.recoverFailure
13-
import pro.azhidkov.platform.spring.mvc.viewId
9+
import pro.azhidkov.platform.kotlin.value
10+
import pro.azhidkov.platform.spring.http.hxRedirect
1411
import pro.qyoga.app.platform.notFound
15-
import pro.qyoga.app.therapist.clients.ClientPageFragmentModel
1612
import pro.qyoga.app.therapist.clients.ClientPageModel
1713
import pro.qyoga.app.therapist.clients.ClientPageTab
1814
import pro.qyoga.core.clients.cards.ClientsRepo
1915
import pro.qyoga.core.clients.cards.dtos.ClientCardDto
2016
import pro.qyoga.core.clients.cards.errors.DuplicatedPhoneException
17+
import pro.qyoga.core.clients.cards.model.Client
2118
import pro.qyoga.core.clients.cards.patchedBy
2219
import java.util.*
2320

24-
data class EditClientCardPageModel(
25-
private val formAction: String
26-
) : ClientPageFragmentModel,
27-
ModelAndView(
28-
viewId("/therapist/clients/client-edit"),
29-
mapOf(
30-
"formAction" to formAction
31-
)
32-
) {
33-
34-
override val model: ModelMap = super<ModelAndView>.modelMap
35-
36-
}
3721

3822
@Controller
3923
class EditClientCardPageController(
@@ -50,34 +34,26 @@ class EditClientCardPageController(
5034
return ClientPageModel(
5135
client,
5236
ClientPageTab.CARD,
53-
EditClientCardPageModel(
54-
"/therapist/clients/${client.id}/card"
55-
)
37+
EditClientCardPageModel(formAction(client.id))
5638
)
5739
}
5840

5941
@PostMapping(EDIT_CLIENT_CARD_PAGE_PATH)
6042
fun editClientCard(
6143
clientCardDto: ClientCardDto,
6244
@PathVariable clientId: UUID
63-
): ModelAndView {
45+
): Any {
6446
val res = runCatching {
6547
clientsRepo.updateById(clientId) { client -> client.patchedBy(clientCardDto) }
6648
}
6749

68-
val modelAndView = res
69-
.mapSuccessOrNull {
70-
ModelAndView("redirect:/therapist/clients")
71-
}
72-
.mapNull {
73-
notFound
74-
}
75-
.recoverFailure { _: DuplicatedPhoneException ->
76-
editClientFormWithValidationError(clientCardDto)
77-
}
78-
.getOrThrow()
50+
return when (res.value()) {
51+
is Client -> hxRedirect("/therapist/clients", "HX-Trigger" to "formSaved")
7952

80-
return modelAndView
53+
null -> notFound
54+
is DuplicatedPhoneException -> editClientFormWithValidationError(formAction(clientId), clientCardDto)
55+
else -> throw res.exceptionOrNull()!!
56+
}
8157
}
8258

8359
companion object {
@@ -86,4 +62,6 @@ class EditClientCardPageController(
8662

8763
}
8864

89-
}
65+
}
66+
67+
private fun formAction(clientId: UUID): String = "/therapist/clients/${clientId}/card"

app/src/main/kotlin/pro/qyoga/app/therapist/clients/cards/EditClientPageModel.kt

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,32 @@
11
package pro.qyoga.app.therapist.clients.cards
22

3+
import org.springframework.ui.ModelMap
4+
import org.springframework.web.servlet.ModelAndView
35
import pro.azhidkov.platform.spring.mvc.modelAndView
6+
import pro.azhidkov.platform.spring.mvc.viewId
7+
import pro.qyoga.app.therapist.clients.ClientPageFragmentModel
48
import pro.qyoga.core.clients.cards.dtos.ClientCardDto
59

10+
data class EditClientCardPageModel(
11+
private val formAction: String,
12+
private val duplicatedPhone: Boolean = false
13+
) : ClientPageFragmentModel,
14+
ModelAndView(
15+
viewId("/therapist/clients/client-edit"),
16+
mapOf(
17+
"formAction" to formAction,
18+
"duplicatedPhone" to duplicatedPhone
19+
)
20+
) {
21+
22+
override val model: ModelMap = super<ModelAndView>.modelMap
23+
24+
}
625

7-
fun editClientFormWithValidationError(clientCardDto: ClientCardDto) =
26+
fun editClientFormWithValidationError(formAction: String, clientCardDto: ClientCardDto) =
827
modelAndView(
928
"therapist/clients/client-create", mapOf(
29+
"formAction" to formAction,
1030
"client" to clientCardDto,
1131
"duplicatedPhone" to true
1232
)

app/src/main/kotlin/pro/qyoga/app/therapist/clients/journal/edit_entry/create/CreateJournalEntryPageController.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class CreateJournalEntryPageController(
6868

6969
return when {
7070
result.isSuccess ->
71-
hxRedirect("/therapist/clients/$clientId/journal")
71+
hxRedirect("/therapist/clients/$clientId/journal", "HX-Trigger" to "formSaved")
7272

7373
result.isFailureOf<DuplicatedDate>() -> {
7474
val ex = result.exceptionOrNull() as DuplicatedDate

app/src/main/kotlin/pro/qyoga/app/therapist/clients/journal/edit_entry/edit/EditJournalEntryPageController.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ import pro.qyoga.core.clients.cards.model.ClientRef
1212
import pro.qyoga.core.clients.journals.JournalEntriesRepo
1313
import pro.qyoga.core.clients.journals.dtos.EditJournalEntryRq
1414
import pro.qyoga.core.clients.journals.errors.DuplicatedDate
15+
import pro.qyoga.core.clients.journals.model.JournalEntry
1516
import pro.qyoga.core.users.auth.dtos.QyogaUserDetails
1617
import java.util.*
1718

1819

1920
@Controller
2021
class EditJournalEntryPageController(
21-
private val journalsEntriesRepo: JournalEntriesRepo,
22-
private val getJournalEntry: GetJournalEntryOp,
22+
private val journalEntriesRepo: JournalEntriesRepo,
2323
private val editJournalEntry: EditJournalEntryOp,
2424
) {
2525

@@ -28,7 +28,7 @@ class EditJournalEntryPageController(
2828
@PathVariable clientId: UUID,
2929
@PathVariable entryId: Long
3030
): ModelAndView {
31-
val result = getJournalEntry.getJournalEntry(clientId, entryId)
31+
val result = journalEntriesRepo.getEntry(clientId, entryId, fetch = JournalEntry.Fetch.summaryRefs)
3232
?: return notFound
3333

3434
return EditJournalEntryPageModel(
@@ -47,7 +47,7 @@ class EditJournalEntryPageController(
4747
): Any {
4848
try {
4949
editJournalEntry(ClientRef.to(clientId), entryId, editJournalEntryRq, principal)
50-
return hxRedirect("/therapist/clients/$clientId/journal")
50+
return hxRedirect("/therapist/clients/$clientId/journal", "HX-Trigger" to "formSaved")
5151
} catch (ex: DuplicatedDate) {
5252
return EditJournalEntryPageModel(
5353
ex.duplicatedEntry.clientRef,
@@ -65,7 +65,7 @@ class EditJournalEntryPageController(
6565
@PathVariable clientId: UUID,
6666
@PathVariable entryId: Long,
6767
) {
68-
journalsEntriesRepo.deleteById(entryId)
68+
journalEntriesRepo.deleteById(entryId)
6969
}
7070

7171
companion object {

app/src/main/kotlin/pro/qyoga/app/therapist/clients/journal/edit_entry/edit/GetJournalEntryOp.kt

Lines changed: 0 additions & 25 deletions
This file was deleted.

0 commit comments

Comments
 (0)