mirror of
https://github.com/go-gitea/gitea.git
synced 2024-12-23 23:18:10 +08:00
792b4dba2c
* update github.com/blevesearch/bleve v2.0.2 -> v2.0.3 * github.com/denisenkom/go-mssqldb v0.9.0 -> v0.10.0 * github.com/editorconfig/editorconfig-core-go v2.4.1 -> v2.4.2 * github.com/go-chi/cors v1.1.1 -> v1.2.0 * github.com/go-git/go-billy v5.0.0 -> v5.1.0 * github.com/go-git/go-git v5.2.0 -> v5.3.0 * github.com/go-ldap/ldap v3.2.4 -> v3.3.0 * github.com/go-redis/redis v8.6.0 -> v8.8.2 * github.com/go-sql-driver/mysql v1.5.0 -> v1.6.0 * github.com/go-swagger/go-swagger v0.26.1 -> v0.27.0 * github.com/lib/pq v1.9.0 -> v1.10.1 * github.com/mattn/go-sqlite3 v1.14.6 -> v1.14.7 * github.com/go-testfixtures/testfixtures v3.5.0 -> v3.6.0 * github.com/issue9/identicon v1.0.1 -> v1.2.0 * github.com/klauspost/compress v1.11.8 -> v1.12.1 * github.com/mgechev/revive v1.0.3 -> v1.0.6 * github.com/microcosm-cc/bluemonday v1.0.7 -> v1.0.8 * github.com/niklasfasching/go-org v1.4.0 -> v1.5.0 * github.com/olivere/elastic v7.0.22 -> v7.0.24 * github.com/pelletier/go-toml v1.8.1 -> v1.9.0 * github.com/prometheus/client_golang v1.9.0 -> v1.10.0 * github.com/xanzy/go-gitlab v0.44.0 -> v0.48.0 * github.com/yuin/goldmark v1.3.3 -> v1.3.5 * github.com/6543/go-version v1.2.4 -> v1.3.1 * do github.com/lib/pq v1.10.0 -> v1.10.1 again ...
321 lines
8.0 KiB
Go
Vendored
321 lines
8.0 KiB
Go
Vendored
// Copyright 2015 go-swagger maintainers
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package strfmt
|
|
|
|
import (
|
|
"encoding"
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/go-openapi/errors"
|
|
"github.com/mitchellh/mapstructure"
|
|
)
|
|
|
|
// Default is the default formats registry
|
|
var Default = NewSeededFormats(nil, nil)
|
|
|
|
// Validator represents a validator for a string format.
|
|
type Validator func(string) bool
|
|
|
|
// Format represents a string format.
|
|
//
|
|
// All implementations of Format provide a string representation and text
|
|
// marshaling/unmarshaling interface to be used by encoders (e.g. encoding/json).
|
|
type Format interface {
|
|
String() string
|
|
encoding.TextMarshaler
|
|
encoding.TextUnmarshaler
|
|
}
|
|
|
|
// Registry is a registry of string formats, with a validation method.
|
|
type Registry interface {
|
|
Add(string, Format, Validator) bool
|
|
DelByName(string) bool
|
|
GetType(string) (reflect.Type, bool)
|
|
ContainsName(string) bool
|
|
Validates(string, string) bool
|
|
Parse(string, string) (interface{}, error)
|
|
MapStructureHookFunc() mapstructure.DecodeHookFunc
|
|
}
|
|
|
|
type knownFormat struct {
|
|
Name string
|
|
OrigName string
|
|
Type reflect.Type
|
|
Validator Validator
|
|
}
|
|
|
|
// NameNormalizer is a function that normalizes a format name.
|
|
type NameNormalizer func(string) string
|
|
|
|
// DefaultNameNormalizer removes all dashes
|
|
func DefaultNameNormalizer(name string) string {
|
|
return strings.ReplaceAll(name, "-", "")
|
|
}
|
|
|
|
type defaultFormats struct {
|
|
sync.Mutex
|
|
data []knownFormat
|
|
normalizeName NameNormalizer
|
|
}
|
|
|
|
// NewFormats creates a new formats registry seeded with the values from the default
|
|
func NewFormats() Registry {
|
|
return NewSeededFormats(Default.(*defaultFormats).data, nil)
|
|
}
|
|
|
|
// NewSeededFormats creates a new formats registry
|
|
func NewSeededFormats(seeds []knownFormat, normalizer NameNormalizer) Registry {
|
|
if normalizer == nil {
|
|
normalizer = DefaultNameNormalizer
|
|
}
|
|
// copy here, don't modify original
|
|
d := append([]knownFormat(nil), seeds...)
|
|
return &defaultFormats{
|
|
data: d,
|
|
normalizeName: normalizer,
|
|
}
|
|
}
|
|
|
|
// MapStructureHookFunc is a decode hook function for mapstructure
|
|
func (f *defaultFormats) MapStructureHookFunc() mapstructure.DecodeHookFunc {
|
|
return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {
|
|
if from.Kind() != reflect.String {
|
|
return data, nil
|
|
}
|
|
for _, v := range f.data {
|
|
tpe, _ := f.GetType(v.Name)
|
|
if to == tpe {
|
|
switch v.Name {
|
|
case "date":
|
|
d, err := time.Parse(RFC3339FullDate, data.(string))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return Date(d), nil
|
|
case "datetime":
|
|
input := data.(string)
|
|
if len(input) == 0 {
|
|
return nil, fmt.Errorf("empty string is an invalid datetime format")
|
|
}
|
|
return ParseDateTime(input)
|
|
case "duration":
|
|
dur, err := ParseDuration(data.(string))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return Duration(dur), nil
|
|
case "uri":
|
|
return URI(data.(string)), nil
|
|
case "email":
|
|
return Email(data.(string)), nil
|
|
case "uuid":
|
|
return UUID(data.(string)), nil
|
|
case "uuid3":
|
|
return UUID3(data.(string)), nil
|
|
case "uuid4":
|
|
return UUID4(data.(string)), nil
|
|
case "uuid5":
|
|
return UUID5(data.(string)), nil
|
|
case "hostname":
|
|
return Hostname(data.(string)), nil
|
|
case "ipv4":
|
|
return IPv4(data.(string)), nil
|
|
case "ipv6":
|
|
return IPv6(data.(string)), nil
|
|
case "cidr":
|
|
return CIDR(data.(string)), nil
|
|
case "mac":
|
|
return MAC(data.(string)), nil
|
|
case "isbn":
|
|
return ISBN(data.(string)), nil
|
|
case "isbn10":
|
|
return ISBN10(data.(string)), nil
|
|
case "isbn13":
|
|
return ISBN13(data.(string)), nil
|
|
case "creditcard":
|
|
return CreditCard(data.(string)), nil
|
|
case "ssn":
|
|
return SSN(data.(string)), nil
|
|
case "hexcolor":
|
|
return HexColor(data.(string)), nil
|
|
case "rgbcolor":
|
|
return RGBColor(data.(string)), nil
|
|
case "byte":
|
|
return Base64(data.(string)), nil
|
|
case "password":
|
|
return Password(data.(string)), nil
|
|
case "ulid":
|
|
ulid, err := ParseULID(data.(string))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return ulid, nil
|
|
default:
|
|
return nil, errors.InvalidTypeName(v.Name)
|
|
}
|
|
}
|
|
}
|
|
return data, nil
|
|
}
|
|
}
|
|
|
|
// Add adds a new format, return true if this was a new item instead of a replacement
|
|
func (f *defaultFormats) Add(name string, strfmt Format, validator Validator) bool {
|
|
f.Lock()
|
|
defer f.Unlock()
|
|
|
|
nme := f.normalizeName(name)
|
|
|
|
tpe := reflect.TypeOf(strfmt)
|
|
if tpe.Kind() == reflect.Ptr {
|
|
tpe = tpe.Elem()
|
|
}
|
|
|
|
for i := range f.data {
|
|
v := &f.data[i]
|
|
if v.Name == nme {
|
|
v.Type = tpe
|
|
v.Validator = validator
|
|
return false
|
|
}
|
|
}
|
|
|
|
// turns out it's new after all
|
|
f.data = append(f.data, knownFormat{Name: nme, OrigName: name, Type: tpe, Validator: validator})
|
|
return true
|
|
}
|
|
|
|
// GetType gets the type for the specified name
|
|
func (f *defaultFormats) GetType(name string) (reflect.Type, bool) {
|
|
f.Lock()
|
|
defer f.Unlock()
|
|
nme := f.normalizeName(name)
|
|
for _, v := range f.data {
|
|
if v.Name == nme {
|
|
return v.Type, true
|
|
}
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
// DelByName removes the format by the specified name, returns true when an item was actually removed
|
|
func (f *defaultFormats) DelByName(name string) bool {
|
|
f.Lock()
|
|
defer f.Unlock()
|
|
|
|
nme := f.normalizeName(name)
|
|
|
|
for i, v := range f.data {
|
|
if v.Name == nme {
|
|
f.data[i] = knownFormat{} // release
|
|
f.data = append(f.data[:i], f.data[i+1:]...)
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// DelByFormat removes the specified format, returns true when an item was actually removed
|
|
func (f *defaultFormats) DelByFormat(strfmt Format) bool {
|
|
f.Lock()
|
|
defer f.Unlock()
|
|
|
|
tpe := reflect.TypeOf(strfmt)
|
|
if tpe.Kind() == reflect.Ptr {
|
|
tpe = tpe.Elem()
|
|
}
|
|
|
|
for i, v := range f.data {
|
|
if v.Type == tpe {
|
|
f.data[i] = knownFormat{} // release
|
|
f.data = append(f.data[:i], f.data[i+1:]...)
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// ContainsName returns true if this registry contains the specified name
|
|
func (f *defaultFormats) ContainsName(name string) bool {
|
|
f.Lock()
|
|
defer f.Unlock()
|
|
nme := f.normalizeName(name)
|
|
for _, v := range f.data {
|
|
if v.Name == nme {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// ContainsFormat returns true if this registry contains the specified format
|
|
func (f *defaultFormats) ContainsFormat(strfmt Format) bool {
|
|
f.Lock()
|
|
defer f.Unlock()
|
|
tpe := reflect.TypeOf(strfmt)
|
|
if tpe.Kind() == reflect.Ptr {
|
|
tpe = tpe.Elem()
|
|
}
|
|
|
|
for _, v := range f.data {
|
|
if v.Type == tpe {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Validates passed data against format.
|
|
//
|
|
// Note that the format name is automatically normalized, e.g. one may
|
|
// use "date-time" to use the "datetime" format validator.
|
|
func (f *defaultFormats) Validates(name, data string) bool {
|
|
f.Lock()
|
|
defer f.Unlock()
|
|
nme := f.normalizeName(name)
|
|
for _, v := range f.data {
|
|
if v.Name == nme {
|
|
return v.Validator(data)
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Parse a string into the appropriate format representation type.
|
|
//
|
|
// E.g. parsing a string a "date" will return a Date type.
|
|
func (f *defaultFormats) Parse(name, data string) (interface{}, error) {
|
|
f.Lock()
|
|
defer f.Unlock()
|
|
nme := f.normalizeName(name)
|
|
for _, v := range f.data {
|
|
if v.Name == nme {
|
|
nw := reflect.New(v.Type).Interface()
|
|
if dec, ok := nw.(encoding.TextUnmarshaler); ok {
|
|
if err := dec.UnmarshalText([]byte(data)); err != nil {
|
|
return nil, err
|
|
}
|
|
return nw, nil
|
|
}
|
|
return nil, errors.InvalidTypeName(name)
|
|
}
|
|
}
|
|
return nil, errors.InvalidTypeName(name)
|
|
}
|