165 lines
5.0 KiB
Go
165 lines
5.0 KiB
Go
/*
|
|
* SPDX-FileCopyrightText: 2023 jordi fita mas <jfita@peritasoft.com>
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
*/
|
|
|
|
package form
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"errors"
|
|
"net/mail"
|
|
"net/url"
|
|
"regexp"
|
|
"strconv"
|
|
"time"
|
|
|
|
"dev.tandem.ws/tandem/camper/pkg/database"
|
|
"dev.tandem.ws/tandem/camper/pkg/locale"
|
|
)
|
|
|
|
type Validator struct {
|
|
l *locale.Locale
|
|
AllOK bool
|
|
}
|
|
|
|
func NewValidator(l *locale.Locale) *Validator {
|
|
return &Validator{
|
|
l: l,
|
|
AllOK: true,
|
|
}
|
|
}
|
|
|
|
func (v *Validator) CheckRequired(input *Input, message string) bool {
|
|
return v.Check(input, input.Val != "", message)
|
|
}
|
|
|
|
func (v *Validator) CheckMinLength(input *Input, min int, message string) bool {
|
|
return v.Check(input, len(input.Val) >= min, message)
|
|
}
|
|
|
|
func (v *Validator) CheckExactLength(input *Input, length int, message string) bool {
|
|
return v.Check(input, len(input.Val) == length, message)
|
|
}
|
|
|
|
func (v *Validator) CheckMinInteger(input *Input, min int, message string) bool {
|
|
i, _ := strconv.Atoi(input.Val)
|
|
return v.Check(input, i >= min, message)
|
|
}
|
|
|
|
func (v *Validator) CheckMaxInteger(input *Input, max int, message string) bool {
|
|
i, _ := strconv.Atoi(input.Val)
|
|
return v.Check(input, i <= max, message)
|
|
}
|
|
|
|
func (v *Validator) CheckMinDecimal(input *Input, min float64, message string) bool {
|
|
f, _ := strconv.ParseFloat(input.Val, 64)
|
|
return v.Check(input, f >= min, message)
|
|
}
|
|
|
|
func (v *Validator) CheckValidInteger(input *Input, message string) bool {
|
|
_, err := strconv.Atoi(input.Val)
|
|
return v.Check(input, err == nil, message)
|
|
}
|
|
|
|
func (v *Validator) CheckValidBase64(input *Input, message string) bool {
|
|
_, err := base64.StdEncoding.DecodeString(input.Val)
|
|
return v.Check(input, err == nil, message)
|
|
}
|
|
|
|
func (v *Validator) CheckValidDecimal(input *Input, message string) bool {
|
|
_, err := strconv.ParseFloat(input.Val, 64)
|
|
return v.Check(input, err == nil, message)
|
|
}
|
|
|
|
func (v *Validator) CheckValidEmail(input *Input, message string) bool {
|
|
_, err := mail.ParseAddress(input.Val)
|
|
return v.Check(input, err == nil, message)
|
|
}
|
|
|
|
func (v *Validator) CheckValidURL(input *Input, message string) bool {
|
|
_, err := url.Parse(input.Val)
|
|
return v.Check(input, err == nil, message)
|
|
}
|
|
|
|
func (v *Validator) CheckValidVATIN(ctx context.Context, conn *database.Conn, input *Input, country string, message string) (bool, error) {
|
|
b, err := conn.GetBool(ctx, "select input_is_valid($1 || $2, 'vatin')", country, input.Val)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return v.Check(input, b, message), nil
|
|
}
|
|
|
|
func (v *Validator) CheckValidPhone(ctx context.Context, conn *database.Conn, input *Input, country string, message string) (bool, error) {
|
|
b, err := conn.GetBool(ctx, "select input_is_valid_phone($1, $2)", input.Val, country)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return v.Check(input, b, message), nil
|
|
}
|
|
|
|
func (v *Validator) CheckValidColor(ctx context.Context, conn *database.Conn, input *Input, message string) (bool, error) {
|
|
b, err := conn.GetBool(ctx, "select input_is_valid($1, 'color')", input.Val)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return v.Check(input, b, message), nil
|
|
}
|
|
|
|
func (v *Validator) CheckValidPostalCode(ctx context.Context, conn *database.Conn, input *Input, country string, message string) (bool, error) {
|
|
pattern, err := conn.GetText(ctx, "select '^' || postal_code_regex || '$' from country where country_code = $1", country)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
match, err := regexp.MatchString(pattern, input.Val)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return v.Check(input, match, message), nil
|
|
}
|
|
|
|
func (v *Validator) CheckValidDate(field *Input, message string) bool {
|
|
_, err := time.Parse("2006-01-02", field.Val)
|
|
return v.Check(field, err == nil, message)
|
|
}
|
|
|
|
func (v *Validator) CheckDateAfter(field *Input, beforeField *Input, message string) bool {
|
|
date, _ := time.Parse("2006-01-02", field.Val)
|
|
before, _ := time.Parse("2006-01-02", beforeField.Val)
|
|
return v.Check(field, date.After(before), message)
|
|
}
|
|
|
|
func (v *Validator) CheckPasswordConfirmation(password *Input, confirm *Input, message string) bool {
|
|
return v.Check(confirm, password.Val == confirm.Val, message)
|
|
}
|
|
|
|
func (v *Validator) CheckSelectedOptions(field *Select, message string) bool {
|
|
return v.Check(field, field.validOptionsSelected(), message)
|
|
}
|
|
|
|
func (v *Validator) CheckImageFile(field *File, message string) bool {
|
|
return v.Check(field, field.ContentType == "image/png" || field.ContentType == "image/jpeg", message)
|
|
}
|
|
|
|
func (v *Validator) CheckImageMedia(ctx context.Context, conn *database.Conn, input *Input, message string) (bool, error) {
|
|
id, err := strconv.Atoi(input.Val)
|
|
if err != nil {
|
|
return v.Check(input, false, message), nil
|
|
}
|
|
exists, err := conn.GetBool(ctx, "select exists(select 1 from media join media_content using (content_hash) where media_id = $1 and media_type like 'image/%')", id)
|
|
return v.Check(input, err == nil && exists, message), err
|
|
}
|
|
|
|
type field interface {
|
|
setError(error)
|
|
}
|
|
|
|
func (v *Validator) Check(field field, ok bool, message string) bool {
|
|
if !ok {
|
|
field.setError(errors.New(v.l.Get(message)))
|
|
v.AllOK = false
|
|
}
|
|
return ok
|
|
}
|