improve form errors
This commit is contained in:
parent
49a39f436c
commit
34211970ae
14 changed files with 115 additions and 37 deletions
|
|
@ -11,23 +11,41 @@ import (
|
|||
"gitnet.fr/deblan/budget/database/manager"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
|
||||
"github.com/go-playground/locales/fr"
|
||||
ut "github.com/go-playground/universal-translator"
|
||||
"github.com/go-playground/validator/v10"
|
||||
fr_translations "github.com/go-playground/validator/v10/translations/fr"
|
||||
)
|
||||
|
||||
type UpdateCallback func(*gorm.DB, interface{}, interface{}) (interface{}, error)
|
||||
type CreateCallback func(*gorm.DB, interface{}) (interface{}, error)
|
||||
|
||||
type Error struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Errors validator.ValidationErrorsTranslations `json:"errors"`
|
||||
}
|
||||
|
||||
type Controller struct {
|
||||
Config Configuration
|
||||
Config Configuration
|
||||
Validator *validator.Validate
|
||||
Trans ut.Translator
|
||||
}
|
||||
|
||||
func New() *Controller {
|
||||
c := Controller{}
|
||||
|
||||
fr := fr.New()
|
||||
uni := ut.New(fr, fr)
|
||||
|
||||
trans, _ := uni.GetTranslator("fr")
|
||||
validate := validator.New()
|
||||
fr_translations.RegisterDefaultTranslations(validate, trans)
|
||||
|
||||
c.Validator = validate
|
||||
c.Trans = trans
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
|
|
@ -155,10 +173,13 @@ func (ctrl *Controller) Create(c echo.Context, body interface{}, createCallback
|
|||
})
|
||||
}
|
||||
|
||||
if err := c.Validate(body); err != nil {
|
||||
if err := ctrl.Validator.Struct(body); err != nil {
|
||||
errs := err.(validator.ValidationErrors)
|
||||
|
||||
return c.JSON(400, Error{
|
||||
Code: 400,
|
||||
Message: err.Error(),
|
||||
Message: message.InvalidForm,
|
||||
Errors: errs.Translate(ctrl.Trans),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -211,10 +232,13 @@ func (ctrl *Controller) Update(c echo.Context, body interface{}, updateCallback
|
|||
})
|
||||
}
|
||||
|
||||
if err := c.Validate(body); err != nil {
|
||||
if err := ctrl.Validator.Struct(body); err != nil {
|
||||
errs := err.(validator.ValidationErrors)
|
||||
|
||||
return c.JSON(400, Error{
|
||||
Code: 400,
|
||||
Message: err.Error(),
|
||||
Message: message.InvalidForm,
|
||||
Errors: errs.Translate(ctrl.Trans),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"io"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/labstack/echo/v4"
|
||||
"gitnet.fr/deblan/budget/backend/controller/crud"
|
||||
"gitnet.fr/deblan/budget/backend/message"
|
||||
|
|
@ -86,7 +87,10 @@ func (ctrl *Controller) Create(c echo.Context) error {
|
|||
if err != nil {
|
||||
return c.JSON(400, crud.Error{
|
||||
Code: 400,
|
||||
Message: err.Error(),
|
||||
Message: message.InvalidForm,
|
||||
Errors: validator.ValidationErrorsTranslations{
|
||||
"BankAccount": message.BlankBankAccount,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -96,7 +100,10 @@ func (ctrl *Controller) Create(c echo.Context) error {
|
|||
if count == 0 {
|
||||
return c.JSON(400, crud.Error{
|
||||
Code: 400,
|
||||
Message: "Invalid bank account",
|
||||
Message: message.InvalidForm,
|
||||
Errors: validator.ValidationErrorsTranslations{
|
||||
"BankAccount": message.UnknownBankAccount,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -104,7 +111,10 @@ func (ctrl *Controller) Create(c echo.Context) error {
|
|||
if err != nil {
|
||||
return c.JSON(400, crud.Error{
|
||||
Code: 400,
|
||||
Message: err.Error(),
|
||||
Message: message.InvalidForm,
|
||||
Errors: validator.ValidationErrorsTranslations{
|
||||
"File": message.BlankFile,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +122,10 @@ func (ctrl *Controller) Create(c echo.Context) error {
|
|||
if err != nil {
|
||||
return c.JSON(400, crud.Error{
|
||||
Code: 400,
|
||||
Message: err.Error(),
|
||||
Message: message.InvalidForm,
|
||||
Errors: validator.ValidationErrorsTranslations{
|
||||
"File": message.UnproccessableFile,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -126,7 +139,10 @@ func (ctrl *Controller) Create(c echo.Context) error {
|
|||
if err != nil {
|
||||
return c.JSON(400, crud.Error{
|
||||
Code: 400,
|
||||
Message: err.Error(),
|
||||
Message: message.InvalidForm,
|
||||
Errors: validator.ValidationErrorsTranslations{
|
||||
"File": message.InvalidFile,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
package message
|
||||
|
||||
var (
|
||||
LoginRequired = "Login required"
|
||||
FileNotFound = "File not found"
|
||||
NotFound = "Not found"
|
||||
BadRequest = "Bad request"
|
||||
LoginRequired = "Login required"
|
||||
FileNotFound = "File not found"
|
||||
NotFound = "Not found"
|
||||
BadRequest = "Bad request"
|
||||
InvalidForm = "Le formulaire n'est pas valide"
|
||||
BlankBankAccount = "Le compte bancaire n'est pas renseigné"
|
||||
UnknownBankAccount = "Le compte bancaire n'existe pas"
|
||||
BlankFile = "Le fichier n'est pas renseigné"
|
||||
UnproccessableFile = "Le fichier ne peut être traité"
|
||||
InvalidFile = "Le fichier n'est pas valide"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -21,4 +21,15 @@ const request = async (endpoint, options) => {
|
|||
return fetch(endpoint, createRequestOptions(options)).then((response) => response.json())
|
||||
}
|
||||
|
||||
export { createRequestOptions, request, requestCallback }
|
||||
const requestErrorBuilder = (response) => {
|
||||
let value = response.message
|
||||
const errors = Object.values(response.errors ?? {})
|
||||
|
||||
if (errors.length) {
|
||||
value += `<ul class="px-3 py-0 my-0 pt-1">${errors.map((e) => `<li class="m-0 p-0">${e}</li>`).join('')}</ul>`
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
export { createRequestOptions, request, requestCallback, requestErrorBuilder }
|
||||
|
|
|
|||
|
|
@ -56,10 +56,14 @@ const remove = async (id, callback, callbackError) => {
|
|||
const fixData = (data) => {
|
||||
if (data.blocked_amount) {
|
||||
data.blocked_amount = parseFloat(data.blocked_amount)
|
||||
} else {
|
||||
data.blocked_amount = 0.0
|
||||
}
|
||||
|
||||
if (data.released_amount) {
|
||||
data.released_amount = parseFloat(data.released_amount)
|
||||
} else {
|
||||
data.released_amount = 0.0
|
||||
}
|
||||
|
||||
return data
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
variant="warning"
|
||||
:model-value="true"
|
||||
>
|
||||
{{ form.error }}
|
||||
<div v-html="form.error"></div>
|
||||
</BAlert>
|
||||
<BRow>
|
||||
<BCol>
|
||||
|
|
@ -51,6 +51,7 @@ import FormView from './../../components/crud/FormView.vue'
|
|||
import { ref, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { create, createForm } from '../../models/bank_account'
|
||||
import { requestErrorBuilder } from '../../lib/request'
|
||||
|
||||
const router = useRouter()
|
||||
const form = ref(null)
|
||||
|
|
@ -60,7 +61,7 @@ const doSave = () => {
|
|||
form.value.data,
|
||||
(data) => {
|
||||
if (data.code === 400) {
|
||||
form.value.error = data.message
|
||||
form.value.error = requestErrorBuilder(data)
|
||||
} else {
|
||||
doBack()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
variant="warning"
|
||||
:model-value="true"
|
||||
>
|
||||
{{ form.error }}
|
||||
<div v-html="form.error"></div>
|
||||
</BAlert>
|
||||
<BRow>
|
||||
<BCol>
|
||||
|
|
@ -63,6 +63,7 @@ import FormView from './../../components/crud/FormView.vue'
|
|||
import { ref, onMounted } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { update, remove, getOne, createForm } from '../../models/bank_account'
|
||||
import { requestErrorBuilder } from '../../lib/request'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
|
@ -95,7 +96,7 @@ const doSave = () => {
|
|||
form.value.data,
|
||||
(data) => {
|
||||
if (data.code === 400) {
|
||||
form.value.error = data.message
|
||||
form.value.error = requestErrorBuilder(data)
|
||||
} else {
|
||||
doBack()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
variant="warning"
|
||||
:model-value="true"
|
||||
>
|
||||
{{ form.error }}
|
||||
<div v-html="form.error"></div>
|
||||
</BAlert>
|
||||
<BRow>
|
||||
<BCol>
|
||||
|
|
@ -51,6 +51,7 @@ import FormView from './../../components/crud/FormView.vue'
|
|||
import { ref, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { create, createForm } from '../../models/category'
|
||||
import { requestErrorBuilder } from '../../lib/request'
|
||||
|
||||
const router = useRouter()
|
||||
const form = ref(null)
|
||||
|
|
@ -60,7 +61,7 @@ const doSave = () => {
|
|||
form.value.data,
|
||||
(data) => {
|
||||
if (data.code === 400) {
|
||||
form.value.error = data.message
|
||||
form.value.error = requestErrorBuilder(data)
|
||||
} else {
|
||||
router.replace({ name: 'category_edit', params: { id: data.id } })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@
|
|||
variant="warning"
|
||||
:model-value="true"
|
||||
>
|
||||
{{ form.error }}
|
||||
<div v-html="form.error"></div>
|
||||
</BAlert>
|
||||
<BRow>
|
||||
<BCol
|
||||
|
|
@ -101,6 +101,7 @@ import { ref, onMounted } from 'vue'
|
|||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { update, remove, getOne, createForm } from '../../models/category'
|
||||
import { updateCategories, getOne as getTransactionOne } from '../../models/transaction'
|
||||
import { requestErrorBuilder } from '../../lib/request'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
|
@ -197,7 +198,7 @@ const doSave = () => {
|
|||
form.value.data,
|
||||
(data) => {
|
||||
if (data.code === 400) {
|
||||
form.value.error = data.message
|
||||
form.value.error = requestErrorBuilder(data)
|
||||
} else {
|
||||
form.value = null
|
||||
addTransaction = false
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
variant="warning"
|
||||
:model-value="true"
|
||||
>
|
||||
{{ form.error }}
|
||||
<div v-html="form.error"></div>
|
||||
</BAlert>
|
||||
<BRow>
|
||||
<BCol>
|
||||
|
|
@ -51,6 +51,7 @@ import FormView from './../../components/crud/FormView.vue'
|
|||
import { ref, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { create, createForm } from '../../models/saving_account'
|
||||
import { requestErrorBuilder } from '../../lib/request'
|
||||
|
||||
const router = useRouter()
|
||||
const form = ref(null)
|
||||
|
|
@ -60,7 +61,7 @@ const doSave = () => {
|
|||
form.value.data,
|
||||
(data) => {
|
||||
if (data.code === 400) {
|
||||
form.value.error = data.message
|
||||
form.value.error = requestErrorBuilder(data)
|
||||
} else {
|
||||
doBack()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
variant="warning"
|
||||
:model-value="true"
|
||||
>
|
||||
{{ form.error }}
|
||||
<div v-html="form.error"></div>
|
||||
</BAlert>
|
||||
<BRow>
|
||||
<BCol>
|
||||
|
|
@ -63,6 +63,7 @@ import FormView from './../../components/crud/FormView.vue'
|
|||
import { ref, onMounted } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { update, remove, getOne, createForm } from '../../models/saving_account'
|
||||
import { requestErrorBuilder } from '../../lib/request'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
|
@ -96,7 +97,7 @@ const doSave = () => {
|
|||
form.value.data,
|
||||
(data) => {
|
||||
if (data.code === 400) {
|
||||
form.value.error = data.message
|
||||
form.value.error = requestErrorBuilder(data)
|
||||
} else {
|
||||
doBack()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,8 +54,9 @@
|
|||
<BAlert
|
||||
:model-value="form.error !== null"
|
||||
variant="danger"
|
||||
>{{ form.error }}</BAlert
|
||||
>
|
||||
>
|
||||
<div v-html="form.error"></div>
|
||||
</BAlert>
|
||||
<BForm @submit="doSave">
|
||||
<FormView :form="form" />
|
||||
</BForm>
|
||||
|
|
@ -107,6 +108,7 @@ import { useRouter, RouterView } from 'vue-router'
|
|||
import { getList, getListFields, getListFilters, createForm, importFile } from '../../models/transaction'
|
||||
import { getList as getAccountList } from '../../models/bank_account'
|
||||
import { getList as getCategoryList } from '../../models/category'
|
||||
import { requestErrorBuilder } from '../../lib/request'
|
||||
|
||||
const endpoint = `/api/transaction`
|
||||
const order = ref(getStorage(`${endpoint}:order`))
|
||||
|
|
@ -183,7 +185,7 @@ const doSave = () => {
|
|||
form.value.data,
|
||||
(data) => {
|
||||
if (data.code === 400) {
|
||||
form.value.error = data.message
|
||||
form.value.error = requestErrorBuilder(data)
|
||||
} else {
|
||||
form.value = null
|
||||
formShow.value = false
|
||||
|
|
|
|||
|
|
@ -26,6 +26,14 @@
|
|||
class="p-3"
|
||||
@submit="submit"
|
||||
>
|
||||
<BAlert
|
||||
v-if="form?.error"
|
||||
dismissible
|
||||
variant="warning"
|
||||
:model-value="true"
|
||||
>
|
||||
<div v-html="form.error"></div>
|
||||
</BAlert>
|
||||
<BRow>
|
||||
<BCol>
|
||||
<FormView :form="form" />
|
||||
|
|
@ -36,13 +44,13 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { BContainer, BButton, BForm, BRow, BCol } from 'bootstrap-vue-next'
|
||||
|
||||
import { BContainer, BButton, BForm, BRow, BCol, BAlert } from 'bootstrap-vue-next'
|
||||
import CrudHeader from '../../components/crud/CrudHeader.vue'
|
||||
import FormView from '../../components/crud/FormView.vue'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { create, createForm } from '../../models/user'
|
||||
import { requestErrorBuilder } from '../../lib/request'
|
||||
|
||||
const router = useRouter()
|
||||
const parentRouteName = 'users'
|
||||
|
|
@ -53,7 +61,7 @@ const doSave = () => {
|
|||
form.value.data,
|
||||
(data) => {
|
||||
if (data.code === 400) {
|
||||
form.value.error = data.message
|
||||
form.value.error = requestErrorBuilder(data)
|
||||
} else {
|
||||
doBack()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
variant="warning"
|
||||
:model-value="true"
|
||||
>
|
||||
{{ form.error }}
|
||||
<div v-html="form.error"></div>
|
||||
</BAlert>
|
||||
<BRow>
|
||||
<BCol>
|
||||
|
|
@ -63,6 +63,7 @@ import FormView from './../../components/crud/FormView.vue'
|
|||
import { ref, onMounted } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { update, remove, getOne, createForm } from '../../models/user'
|
||||
import { requestErrorBuilder } from '../../lib/request'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
|
@ -96,7 +97,7 @@ const doSave = () => {
|
|||
form.value.data,
|
||||
(data) => {
|
||||
if (data.code === 400) {
|
||||
form.value.error = data.message
|
||||
form.value.error = requestErrorBuilder(data)
|
||||
} else {
|
||||
doBack()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue