2023-01-31 14:40:12 +00:00
package pkg
import (
"context"
2023-02-01 13:15:02 +00:00
"database/sql/driver"
2023-02-01 10:30:30 +00:00
"errors"
2023-02-01 13:15:02 +00:00
"fmt"
"html/template"
2023-02-01 10:02:32 +00:00
"net/http"
2023-01-31 14:40:12 +00:00
"net/mail"
2023-02-01 13:15:02 +00:00
"net/url"
"regexp"
"strconv"
2023-02-01 10:02:32 +00:00
"strings"
2023-01-31 14:40:12 +00:00
)
2023-02-01 10:02:32 +00:00
type Attribute struct {
Key , Val string
}
2023-01-31 14:40:12 +00:00
type InputField struct {
2023-02-01 10:02:32 +00:00
Name string
Label string
Type string
2023-02-01 13:15:02 +00:00
Val string
2023-02-01 10:02:32 +00:00
Required bool
2023-02-01 13:15:02 +00:00
Attributes [ ] template . HTMLAttr
2023-02-01 10:02:32 +00:00
Errors [ ] error
}
2023-02-01 13:15:02 +00:00
func ( field * InputField ) Scan ( value interface { } ) error {
if value == nil {
field . Val = ""
return nil
}
field . Val = fmt . Sprintf ( "%v" , value )
return nil
}
func ( field * InputField ) Value ( ) ( driver . Value , error ) {
return field . Val , nil
}
2023-02-01 10:02:32 +00:00
func ( field * InputField ) FillValue ( r * http . Request ) {
2023-02-01 13:15:02 +00:00
field . Val = strings . TrimSpace ( r . FormValue ( field . Name ) )
}
func ( field * InputField ) Integer ( ) int {
value , _ := strconv . Atoi ( field . Val )
return value
2023-01-31 14:40:12 +00:00
}
type SelectOption struct {
Value string
Label string
}
type SelectField struct {
2023-02-01 13:15:02 +00:00
Name string
Label string
Selected string
Options [ ] * SelectOption
Attributes [ ] template . HTMLAttr
Errors [ ] error
}
func ( field * SelectField ) Scan ( value interface { } ) error {
if value == nil {
field . Selected = ""
return nil
}
field . Selected = fmt . Sprintf ( "%v" , value )
return nil
}
func ( field * SelectField ) Value ( ) ( driver . Value , error ) {
return field . Selected , nil
2023-01-31 14:40:12 +00:00
}
2023-02-01 10:02:32 +00:00
func ( field * SelectField ) FillValue ( r * http . Request ) {
field . Selected = r . FormValue ( field . Name )
}
2023-01-31 14:40:12 +00:00
func ( field * SelectField ) HasValidOption ( ) bool {
for _ , option := range field . Options {
if option . Value == field . Selected {
return true
}
}
return false
}
func MustGetOptions ( ctx context . Context , conn * Conn , sql string , args ... interface { } ) [ ] * SelectOption {
rows , err := conn . Query ( ctx , sql , args ... )
if err != nil {
panic ( err )
}
defer rows . Close ( )
var options [ ] * SelectOption
for rows . Next ( ) {
option := & SelectOption { }
err = rows . Scan ( & option . Value , & option . Label )
if err != nil {
panic ( err )
}
options = append ( options , option )
}
if rows . Err ( ) != nil {
panic ( rows . Err ( ) )
}
return options
}
2023-02-01 10:30:30 +00:00
2023-02-01 13:15:02 +00:00
func mustGetCountryOptions ( ctx context . Context , conn * Conn , locale * Locale ) [ ] * SelectOption {
return MustGetOptions ( ctx , conn , "select country.country_code, coalesce(i18n.name, country.name) as l10n_name from country left join country_i18n as i18n on country.country_code = i18n.country_code and i18n.lang_tag = $1 order by l10n_name" , locale . Language )
}
2023-02-01 10:30:30 +00:00
type FormValidator struct {
Valid bool
}
func newFormValidator ( ) * FormValidator {
return & FormValidator { true }
}
func ( v * FormValidator ) AllOK ( ) bool {
return v . Valid
}
func ( v * FormValidator ) CheckRequiredInput ( field * InputField , message string ) bool {
2023-02-01 13:15:02 +00:00
return v . checkInput ( field , field . Val != "" , message )
2023-02-01 10:30:30 +00:00
}
func ( v * FormValidator ) CheckValidEmailInput ( field * InputField , message string ) bool {
2023-02-01 13:15:02 +00:00
_ , err := mail . ParseAddress ( field . Val )
2023-02-01 10:30:30 +00:00
return v . checkInput ( field , err == nil , message )
}
2023-02-01 13:15:02 +00:00
func ( v * FormValidator ) CheckValidVATINInput ( field * InputField , country string , message string ) bool {
// TODO: actual VATIN validation
return v . checkInput ( field , true , message )
}
func ( v * FormValidator ) CheckValidPhoneInput ( field * InputField , country string , message string ) bool {
// TODO: actual phone validation
return v . checkInput ( field , true , message )
}
2023-02-01 10:30:30 +00:00
func ( v * FormValidator ) CheckPasswordConfirmation ( password * InputField , confirm * InputField , message string ) bool {
2023-02-01 13:15:02 +00:00
return v . checkInput ( confirm , password . Val == confirm . Val , message )
2023-02-01 10:30:30 +00:00
}
func ( v * FormValidator ) CheckValidSelectOption ( field * SelectField , message string ) bool {
return v . checkSelect ( field , field . HasValidOption ( ) , message )
}
2023-02-01 13:15:02 +00:00
func ( v * FormValidator ) checkValidURL ( field * InputField , message string ) bool {
_ , err := url . ParseRequestURI ( field . Val )
return v . checkInput ( field , err == nil , message )
}
func ( v * FormValidator ) CheckValidPostalCode ( ctx context . Context , conn * Conn , field * InputField , country string , message string ) bool {
pattern := "^" + conn . MustGetText ( ctx , ".{1,255}" , "select postal_code_regex from country where country_code = $1" , country ) + "$"
match , err := regexp . MatchString ( pattern , field . Val )
if err != nil {
panic ( err )
}
return v . checkInput ( field , match , message )
}
func ( v * FormValidator ) CheckValidInteger ( field * InputField , min int , max int , message string ) bool {
value , err := strconv . Atoi ( field . Val )
return v . checkInput ( field , err == nil && value >= min && value <= max , message )
}
2023-02-01 10:30:30 +00:00
func ( v * FormValidator ) checkInput ( field * InputField , ok bool , message string ) bool {
if ! ok {
field . Errors = append ( field . Errors , errors . New ( message ) )
v . Valid = false
}
return ok
}
func ( v * FormValidator ) checkSelect ( field * SelectField , ok bool , message string ) bool {
if ! ok {
field . Errors = append ( field . Errors , errors . New ( message ) )
v . Valid = false
}
return ok
}