feat: add Go backend
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
// Package validate
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
package validate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// Filter 通用过滤器
|
||||
|
||||
// Filter 预处理和数据过滤接口,目前主要用于input层的输入过滤和内部效验。
|
||||
// 你可以在任意地方使用它,只要实现了Filter接口即可
|
||||
type Filter interface {
|
||||
// Filter gf效验规则 https://goframe.org/pages/viewpage.action?pageId=1114367
|
||||
Filter(ctx context.Context) error
|
||||
}
|
||||
|
||||
// PreFilter 预过滤
|
||||
func PreFilter(ctx context.Context, in interface{}) error {
|
||||
return g.Try(ctx, func(ctx context.Context) {
|
||||
if c, ok := in.(Filter); ok {
|
||||
if err := c.Filter(ctx); err != nil {
|
||||
g.Throw(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
// Package validate_test
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
package validate_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"hotgo/utility/validate"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// MockFilter 是 Filter 接口的模拟实现。
|
||||
type MockFilter struct {
|
||||
Foo string
|
||||
Bar int
|
||||
}
|
||||
|
||||
func (f *MockFilter) Filter(ctx context.Context) error {
|
||||
// 模拟过滤逻辑
|
||||
|
||||
// 过滤出错的例子
|
||||
if f.Foo == "" {
|
||||
return gerror.New("Foo 字段是必需的")
|
||||
}
|
||||
|
||||
// 过滤操作的例子
|
||||
f.Bar += 10
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestPreFilter(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
input := &MockFilter{
|
||||
Foo: "test",
|
||||
Bar: 5,
|
||||
}
|
||||
|
||||
err := validate.PreFilter(ctx, input)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
t.AssertNil(err)
|
||||
})
|
||||
|
||||
t.Logf("input:%+v", input)
|
||||
|
||||
// 验证过滤结果
|
||||
expectedBar := 15
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
t.Assert(input.Bar, expectedBar)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPreFilter_Error(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
input := &MockFilter{
|
||||
Foo: "",
|
||||
Bar: 5,
|
||||
}
|
||||
|
||||
err := validate.PreFilter(ctx, input)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
t.AssertNE(err, nil)
|
||||
})
|
||||
|
||||
expectedError := "Foo 字段是必需的"
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
t.Assert(err.Error(), expectedError)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Package validate
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
package validate
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// 包含判断
|
||||
|
||||
// InSliceExistStr 判断字符或切片字符是否存在指定字符
|
||||
func InSliceExistStr(elems any, search string) bool {
|
||||
switch elems.(type) {
|
||||
case []string:
|
||||
elem := gconv.Strings(elems)
|
||||
for i := 0; i < len(elem); i++ {
|
||||
if gconv.String(elem[i]) == search {
|
||||
return true
|
||||
}
|
||||
}
|
||||
default:
|
||||
return gconv.String(elems) == search
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// InSlice 元素是否存在于切片中
|
||||
func InSlice[K comparable](slice []K, key K) bool {
|
||||
for _, v := range slice {
|
||||
if v == key {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
// Package validate
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
package validate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"net"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 是否判断
|
||||
|
||||
// IsDNSName 是否是域名地址
|
||||
func IsDNSName(s string) bool {
|
||||
DNSName := `^([a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*[\._]?$`
|
||||
rxDNSName := regexp.MustCompile(DNSName)
|
||||
return s != "" && rxDNSName.MatchString(s)
|
||||
}
|
||||
|
||||
// IsHTTPS 是否是https请求
|
||||
func IsHTTPS(ctx context.Context) bool {
|
||||
r := ghttp.RequestFromCtx(ctx)
|
||||
if r == nil {
|
||||
g.Log().Info(ctx, "IsHTTPS ctx not request")
|
||||
return false
|
||||
}
|
||||
return r.TLS != nil || gstr.Equal(r.Header.Get("X-Forwarded-Proto"), "https")
|
||||
}
|
||||
|
||||
// IsIp 是否为ipv4
|
||||
func IsIp(ip string) bool {
|
||||
return net.ParseIP(ip) != nil
|
||||
}
|
||||
|
||||
// IsPublicIp 是否是公网IP
|
||||
func IsPublicIp(ip string) bool {
|
||||
i := net.ParseIP(ip)
|
||||
|
||||
if i.IsLoopback() || i.IsPrivate() || i.IsMulticast() || i.IsUnspecified() || i.IsLinkLocalUnicast() || i.IsLinkLocalMulticast() {
|
||||
return false
|
||||
}
|
||||
|
||||
if ip4 := i.To4(); ip4 != nil {
|
||||
return !i.Equal(net.IPv4bcast)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// IsLocalIPAddr 检测 IP 地址字符串是否是内网地址
|
||||
func IsLocalIPAddr(ip string) bool {
|
||||
if "localhost" == ip {
|
||||
return true
|
||||
}
|
||||
return HasLocalIP(net.ParseIP(ip))
|
||||
}
|
||||
|
||||
// HasLocalIP 检测 IP 地址是否是内网地址
|
||||
func HasLocalIP(ip net.IP) bool {
|
||||
if ip.IsLoopback() {
|
||||
return true
|
||||
}
|
||||
|
||||
ip4 := ip.To4()
|
||||
if ip4 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return ip4[0] == 10 || // 10.0.0.0/8
|
||||
(ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31) || // 172.16.0.0/12
|
||||
(ip4[0] == 169 && ip4[1] == 254) || // 169.254.0.0/16
|
||||
(ip4[0] == 192 && ip4[1] == 168) // 192.168.0.0/16
|
||||
}
|
||||
|
||||
// IsMobile 是否为手机号码
|
||||
func IsMobile(mobile string) bool {
|
||||
pattern := `^(1[2|3|4|5|6|7|8|9][0-9]\d{4,8})$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
return reg.MatchString(mobile)
|
||||
}
|
||||
|
||||
// IsEmail 是否为邮箱地址
|
||||
func IsEmail(email string) bool {
|
||||
// pattern := `^[0-9a-z][_.0-9a-z-]{0,31}@([0-9a-z][0-9a-z-]{0,30}[0-9a-z].){1,4}[a-z]{2,4}$` //匹配电子邮箱
|
||||
pattern := `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
return reg.MatchString(email)
|
||||
}
|
||||
|
||||
// IsURL 是否是url地址
|
||||
func IsURL(u string) bool {
|
||||
_, err := url.ParseRequestURI(u)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
URL, err := url.Parse(u)
|
||||
if err != nil || URL.Scheme == "" || URL.Host == "" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// IsIDCard 是否为身份证
|
||||
func IsIDCard(idCard string) bool {
|
||||
sz := len(idCard)
|
||||
if sz != 18 {
|
||||
return false
|
||||
}
|
||||
weight := []int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
|
||||
validate := []byte{'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'}
|
||||
sum := 0
|
||||
for i := 0; i < len(weight); i++ {
|
||||
sum += weight[i] * int(byte(idCard[i])-'0')
|
||||
}
|
||||
m := sum % 11
|
||||
return validate[m] == idCard[sz-1]
|
||||
}
|
||||
|
||||
// IsSameDay 是否为同一天
|
||||
func IsSameDay(t1, t2 int64) bool {
|
||||
y1, m1, d1 := time.Unix(t1, 0).Date()
|
||||
y2, m2, d2 := time.Unix(t2, 0).Date()
|
||||
return y1 == y2 && m1 == m2 && d1 == d2
|
||||
}
|
||||
|
||||
// IsSameMinute 是否为同一分钟
|
||||
func IsSameMinute(t1, t2 int64) bool {
|
||||
d1 := time.Unix(t1, 0).Format("2006-01-02 15:04")
|
||||
d2 := time.Unix(t2, 0).Format("2006-01-02 15:04")
|
||||
return d1 == d2
|
||||
}
|
||||
|
||||
// IsMobileVisit 是否为移动端访问
|
||||
func IsMobileVisit(userAgent string) bool {
|
||||
if len(userAgent) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
is := false
|
||||
mobileKeywords := []string{"Mobile", "Android", "Silk/", "Kindle", "BlackBerry", "Opera Mini", "Opera Mobi"}
|
||||
for i := 0; i < len(mobileKeywords); i++ {
|
||||
if strings.Contains(userAgent, mobileKeywords[i]) {
|
||||
is = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return is
|
||||
}
|
||||
|
||||
// IsWxBrowserVisit 是否为微信访问
|
||||
func IsWxBrowserVisit(userAgent string) bool {
|
||||
if len(userAgent) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
is := false
|
||||
userAgent = strings.ToLower(userAgent)
|
||||
mobileKeywords := []string{"MicroMessenger"}
|
||||
for i := 0; i < len(mobileKeywords); i++ {
|
||||
if strings.Contains(userAgent, strings.ToLower(mobileKeywords[i])) {
|
||||
is = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return is
|
||||
}
|
||||
|
||||
// IsWxMiniProgramVisit 是否为微信小程序访问
|
||||
func IsWxMiniProgramVisit(userAgent string) bool {
|
||||
if len(userAgent) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
is := false
|
||||
userAgent = strings.ToLower(userAgent)
|
||||
mobileKeywords := []string{"miniProgram"}
|
||||
for i := 0; i < len(mobileKeywords); i++ {
|
||||
if strings.Contains(userAgent, strings.ToLower(mobileKeywords[i])) {
|
||||
is = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return is
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Package validate_test
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
package validate_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"hotgo/utility/validate"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIsEmail(t *testing.T) {
|
||||
b := validate.IsEmail("QTT123456@163.com")
|
||||
gtest.Assert(true, b)
|
||||
}
|
||||
Reference in New Issue
Block a user