Initial commit (code only without large binaries)
This commit is contained in:
8
EdgeCommon/pkg/systemconfigs/admin_module.go
Normal file
8
EdgeCommon/pkg/systemconfigs/admin_module.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package systemconfigs
|
||||
|
||||
// AdminModule 管理用户模块权限
|
||||
type AdminModule struct {
|
||||
Code string `json:"code"` // 模块代号
|
||||
AllowAll bool `json:"allowAll"` // 允许所有的动作
|
||||
Actions []string `json:"actions"` // 只允许的动作
|
||||
}
|
||||
31
EdgeCommon/pkg/systemconfigs/admin_ui_config.go
Normal file
31
EdgeCommon/pkg/systemconfigs/admin_ui_config.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package systemconfigs
|
||||
|
||||
// AdminUIConfig 管理员界面相关配置
|
||||
type AdminUIConfig struct {
|
||||
ProductName string `json:"productName"` // 产品名
|
||||
AdminSystemName string `json:"adminSystemName"` // 管理员系统名称
|
||||
ShowOpenSourceInfo bool `json:"showOpenSourceInfo"` // 是否显示开源信息
|
||||
ShowVersion bool `json:"showVersion"` // 是否显示版本号
|
||||
Version string `json:"version"` // 显示的版本号
|
||||
ShowFinance bool `json:"showFinance"` // 是否显示财务相关信息
|
||||
FaviconFileId int64 `json:"faviconFileId"` // Favicon文件ID
|
||||
LogoFileId int64 `json:"logoFileId"` // Logo文件ID
|
||||
DefaultPageSize int `json:"defaultPageSize"` // 默认每页显示数
|
||||
TimeZone string `json:"timeZone"` // 时区
|
||||
Modules []string `json:"modules"` // 开通模块
|
||||
DNSResolver struct {
|
||||
Type string `json:"type"` // 类型,参考 DNSResolverType*
|
||||
} `json:"dnsResolver"` // DNS解析设置
|
||||
}
|
||||
|
||||
func (this *AdminUIConfig) ContainsModule(module string) bool {
|
||||
if len(this.Modules) == 0 {
|
||||
return true
|
||||
}
|
||||
for _, m := range this.Modules {
|
||||
if m == module {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
17
EdgeCommon/pkg/systemconfigs/bandwidth.go
Normal file
17
EdgeCommon/pkg/systemconfigs/bandwidth.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package systemconfigs
|
||||
|
||||
type BandwidthUnit = string
|
||||
|
||||
const (
|
||||
BandwidthUnitByte BandwidthUnit = "byte"
|
||||
BandwidthUnitBit BandwidthUnit = "bit"
|
||||
)
|
||||
|
||||
type BandwidthAlgo = string // 带宽算法
|
||||
|
||||
const (
|
||||
BandwidthAlgoSecondly BandwidthAlgo = "secondly" // 按秒算
|
||||
BandwidthAlgoAvg BandwidthAlgo = "avg" // N分钟平均
|
||||
)
|
||||
15
EdgeCommon/pkg/systemconfigs/check_updates_config.go
Normal file
15
EdgeCommon/pkg/systemconfigs/check_updates_config.go
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package systemconfigs
|
||||
|
||||
// CheckUpdatesConfig 检查更新配置
|
||||
type CheckUpdatesConfig struct {
|
||||
AutoCheck bool `yaml:"autoCheck" json:"autoCheck"` // 是否开启自动检查
|
||||
IgnoredVersion string `yaml:"ignoredVersion" json:"ignoredVersion"` // 上次忽略的版本
|
||||
}
|
||||
|
||||
func NewCheckUpdatesConfig() *CheckUpdatesConfig {
|
||||
return &CheckUpdatesConfig{
|
||||
AutoCheck: true,
|
||||
}
|
||||
}
|
||||
13
EdgeCommon/pkg/systemconfigs/clickhouse_setting.go
Normal file
13
EdgeCommon/pkg/systemconfigs/clickhouse_setting.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package systemconfigs
|
||||
|
||||
// ClickHouseSetting 后台页面配置的 ClickHouse 连接(访问日志 logs_ingest 查询)
|
||||
type ClickHouseSetting struct {
|
||||
Host string `json:"host" yaml:"host"`
|
||||
Port int `json:"port" yaml:"port"`
|
||||
User string `json:"user" yaml:"user"`
|
||||
Password string `json:"password" yaml:"password"`
|
||||
Database string `json:"database" yaml:"database"`
|
||||
Scheme string `json:"scheme" yaml:"scheme"`
|
||||
TLSSkipVerify bool `json:"tlsSkipVerify" yaml:"tlsSkipVerify"`
|
||||
TLSServerName string `json:"tlsServerName" yaml:"tlsServerName"`
|
||||
}
|
||||
93
EdgeCommon/pkg/systemconfigs/database_config.go
Normal file
93
EdgeCommon/pkg/systemconfigs/database_config.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package systemconfigs
|
||||
|
||||
// DatabaseConfig 数据库相关配置
|
||||
type DatabaseConfig struct {
|
||||
ServerAccessLog struct {
|
||||
Clean struct {
|
||||
Days int `json:"days"` // 日志保留天数,0表示不限制
|
||||
} `json:"clean"` // 清理相关配置
|
||||
} `json:"serverAccessLog"` // 服务访问日志相关配置
|
||||
|
||||
HTTPCacheTask struct {
|
||||
Clean struct {
|
||||
Days int `json:"days"`
|
||||
} `json:"clean"`
|
||||
} `json:"httpCacheTask"` // 缓存任务
|
||||
|
||||
NodeTrafficDailyStat struct {
|
||||
Clean struct {
|
||||
Days int `json:"days"`
|
||||
} `json:"clean"`
|
||||
} `json:"nodeTrafficDailyStat"`
|
||||
|
||||
ServerBandwidthStat struct {
|
||||
Clean struct {
|
||||
Days int `json:"days"`
|
||||
} `json:"clean"`
|
||||
} `json:"serverBandwidthStat"`
|
||||
|
||||
ServerDailyStat struct {
|
||||
Clean struct {
|
||||
Days int `json:"days"`
|
||||
} `json:"clean"`
|
||||
} `json:"serverDailyStat"`
|
||||
|
||||
UserBandwidthStat struct {
|
||||
Clean struct {
|
||||
Days int `json:"days"`
|
||||
} `json:"clean"`
|
||||
} `json:"userBandwidthStat"`
|
||||
|
||||
UserPlanBandwidthStat struct {
|
||||
Clean struct {
|
||||
Days int `json:"days"`
|
||||
} `json:"clean"`
|
||||
} `json:"userPlanBandwidthStat"`
|
||||
|
||||
NodeClusterTrafficDailyStat struct {
|
||||
Clean struct {
|
||||
Days int `json:"days"`
|
||||
} `json:"clean"`
|
||||
} `json:"nodeClusterTrafficDailyStat"`
|
||||
|
||||
NodeTrafficHourlyStat struct {
|
||||
Clean struct {
|
||||
Days int `json:"days"`
|
||||
} `json:"clean"`
|
||||
} `json:"nodeTrafficHourlyStat"`
|
||||
|
||||
ServerDomainHourlyStat struct {
|
||||
Clean struct {
|
||||
Days int `json:"days"`
|
||||
} `json:"clean"`
|
||||
} `json:"serverDomainHourlyStat"`
|
||||
|
||||
TrafficDailyStat struct {
|
||||
Clean struct {
|
||||
Days int `json:"days"`
|
||||
} `json:"clean"`
|
||||
} `json:"trafficDailyStat"`
|
||||
|
||||
TrafficHourlyStat struct {
|
||||
Clean struct {
|
||||
Days int `json:"days"`
|
||||
} `json:"clean"`
|
||||
} `json:"trafficHourlyStat"`
|
||||
}
|
||||
|
||||
func NewDatabaseConfig() *DatabaseConfig {
|
||||
var config = &DatabaseConfig{}
|
||||
config.ServerAccessLog.Clean.Days = 14
|
||||
config.HTTPCacheTask.Clean.Days = 30
|
||||
config.NodeTrafficDailyStat.Clean.Days = 32
|
||||
config.ServerBandwidthStat.Clean.Days = 100
|
||||
config.ServerDailyStat.Clean.Days = 60
|
||||
config.UserBandwidthStat.Clean.Days = 100
|
||||
config.UserPlanBandwidthStat.Clean.Days = 100
|
||||
config.NodeClusterTrafficDailyStat.Clean.Days = 30
|
||||
config.NodeTrafficHourlyStat.Clean.Days = 15
|
||||
config.ServerDomainHourlyStat.Clean.Days = 7
|
||||
config.TrafficDailyStat.Clean.Days = 30
|
||||
config.TrafficHourlyStat.Clean.Days = 15
|
||||
return config
|
||||
}
|
||||
26
EdgeCommon/pkg/systemconfigs/log_config.go
Normal file
26
EdgeCommon/pkg/systemconfigs/log_config.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package systemconfigs
|
||||
|
||||
import "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
|
||||
// DefaultLogConfig 默认日志配置
|
||||
func DefaultLogConfig() *LogConfig {
|
||||
return &LogConfig{
|
||||
CanDelete: false,
|
||||
CanClean: false,
|
||||
Capacity: &shared.SizeCapacity{
|
||||
Count: 1,
|
||||
Unit: shared.SizeCapacityUnitGB,
|
||||
},
|
||||
Days: 30,
|
||||
CanChange: true,
|
||||
}
|
||||
}
|
||||
|
||||
// LogConfig 操作日志相关配置
|
||||
type LogConfig struct {
|
||||
CanDelete bool `json:"canDelete"` // 是否可删除
|
||||
CanClean bool `json:"canClean"` // 是否可清理
|
||||
Capacity *shared.SizeCapacity `json:"capacity"` // 容量
|
||||
Days int `json:"days"` // 自动保存天数
|
||||
CanChange bool `json:"canChange"` // 是否允许再次修改配置
|
||||
}
|
||||
41
EdgeCommon/pkg/systemconfigs/security_config.go
Normal file
41
EdgeCommon/pkg/systemconfigs/security_config.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package systemconfigs
|
||||
|
||||
import "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
|
||||
// SecurityConfig 安全相关配置
|
||||
type SecurityConfig struct {
|
||||
Frame string `json:"frame"` // Frame嵌套
|
||||
AllowCountryIds []int64 `json:"allowCountryIds"` // 允许的国家/地区
|
||||
AllowProvinceIds []int64 `json:"allowProvinceIds"` // 允许的省份
|
||||
AllowLocal bool `json:"allowLocal"` // 允许本地+局域网IP访问
|
||||
AllowIPs []string `json:"allowIPs"` // 允许访问的IP
|
||||
AllowRememberLogin bool `json:"allowRememberLogin"` // 是否允许在设备上记住登录
|
||||
DenySearchEngines bool `json:"denySearchEngines"` // 禁止常见的搜索引擎访问
|
||||
DenySpiders bool `json:"denySpiders"` // 禁止常见的爬虫
|
||||
AllowDomains []string `json:"allowDomains"` // 允许访问的域名
|
||||
CheckClientFingerprint bool `json:"checkClientFingerprint"` // 在登录状态下检查客户端指纹
|
||||
CheckClientRegion bool `json:"checkClientRegion"` // 在登录状态下检查客户端区域
|
||||
|
||||
ClientIPHeaderNames string `json:"clientIPHeaderNames"` // 客户端IP获取报头名称列表
|
||||
ClientIPHeaderOnly bool `json:"clientIPHeaderOnly"` // 是否仅从报头中获取IP
|
||||
|
||||
allowIPRanges []*shared.IPRangeConfig
|
||||
}
|
||||
|
||||
// Init 初始化
|
||||
func (this *SecurityConfig) Init() error {
|
||||
this.allowIPRanges = []*shared.IPRangeConfig{}
|
||||
for _, allowIP := range this.AllowIPs {
|
||||
r, err := shared.ParseIPRange(allowIP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
this.allowIPRanges = append(this.allowIPRanges, r)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AllowIPRanges 查询允许的IP区域
|
||||
func (this *SecurityConfig) AllowIPRanges() []*shared.IPRangeConfig {
|
||||
return this.allowIPRanges
|
||||
}
|
||||
20
EdgeCommon/pkg/systemconfigs/settings.go
Normal file
20
EdgeCommon/pkg/systemconfigs/settings.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package systemconfigs
|
||||
|
||||
type SettingCode = string
|
||||
|
||||
const (
|
||||
SettingCodeNodeMonitor SettingCode = "nodeMonitor" // 监控节点状态
|
||||
SettingCodeClusterHealthCheck SettingCode = "clusterHealthCheck" // 集群健康检查
|
||||
SettingCodeIPListVersion SettingCode = "ipListVersion" // IP名单的版本号
|
||||
SettingCodeAdminSecurityConfig SettingCode = "adminSecurityConfig" // 管理员安全设置
|
||||
SettingCodeAdminUIConfig SettingCode = "adminUIConfig" // 管理员界面设置
|
||||
SettingCodeDatabaseConfigSetting SettingCode = "databaseConfig" // 数据库相关配置
|
||||
SettingCodeAccessLogQueue SettingCode = "accessLogQueue" // 访问日志队列
|
||||
SettingCodeCheckUpdates SettingCode = "checkUpdates" // 检查自动更新配置
|
||||
|
||||
SettingCodeUserServerConfig SettingCode = "userServerConfig" // 用户服务设置
|
||||
SettingCodeUserRegisterConfig SettingCode = "userRegisterConfig" // 用户注册配置
|
||||
SettingCodeUserUIConfig SettingCode = "userUIConfig" // 用户界面配置
|
||||
|
||||
SettingCodeStandaloneInstanceInitialized SettingCode = "standaloneInstanceInitialized" // 单体实例是否已经被初始化:0 未被初始化, 1 已经成功初始化
|
||||
)
|
||||
20
EdgeCommon/pkg/systemconfigs/settings_plus.go
Normal file
20
EdgeCommon/pkg/systemconfigs/settings_plus.go
Normal file
@@ -0,0 +1,20 @@
|
||||
//go:build plus
|
||||
|
||||
package systemconfigs
|
||||
|
||||
const (
|
||||
SettingCodeUserPriceConfig SettingCode = "userPriceConfig" // 用户计费设置
|
||||
SettingCodeUserOrderConfig SettingCode = "userOrderConfig" // 用户订单设置
|
||||
SettingCodeUserSenderConfig SettingCode = "userSenderConfig" // 用户媒介发送设置(邮件、短信等)
|
||||
|
||||
SettingCodeNSAccessLogSetting SettingCode = "nsAccessLogSetting" // NS相关全局配置
|
||||
SettingCodeNSUserConfig SettingCode = "nsUserConfig" // NS用户相关设置
|
||||
SettingCodeNSNodeMonitor SettingCode = "nsNodeMonitor" // 监控NS节点状态
|
||||
|
||||
SettingCodeReportNodeGlobalSetting SettingCode = "reportNodeGlobalSetting" // 区域监控节点全局配置
|
||||
|
||||
SettingCodeBillDay SettingCode = "billDay" // 账单日 YYYYMMDD
|
||||
SettingCodeBillMonth SettingCode = "billMonth" // 账单月 YYYYMM
|
||||
|
||||
SettingCodeClickHouseConfig SettingCode = "clickhouseConfig" // ClickHouse 连接配置(访问日志 logs_ingest 查询)
|
||||
)
|
||||
25
EdgeCommon/pkg/systemconfigs/theme_config.go
Normal file
25
EdgeCommon/pkg/systemconfigs/theme_config.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package systemconfigs
|
||||
|
||||
func DefaultThemeBackgroundColors() []string {
|
||||
return []string{
|
||||
"14539A",
|
||||
"276AC6",
|
||||
"0081AF",
|
||||
"473BF0",
|
||||
"ACADBC",
|
||||
"9B9ECE",
|
||||
"C96480",
|
||||
"B47978",
|
||||
"B1AE91",
|
||||
"49A078",
|
||||
"46237A",
|
||||
"000500",
|
||||
}
|
||||
}
|
||||
|
||||
// ThemeConfig 风格模板设置
|
||||
type ThemeConfig struct {
|
||||
BackgroundColor string `yaml:"backgroundColor" json:"backgroundColor"` // 背景色,16进制,不需要带井号(#)
|
||||
}
|
||||
146
EdgeCommon/pkg/systemconfigs/user_ui_config.go
Normal file
146
EdgeCommon/pkg/systemconfigs/user_ui_config.go
Normal file
@@ -0,0 +1,146 @@
|
||||
package systemconfigs
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/types"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
// UserUIConfig 用户界面相关配置
|
||||
type UserUIConfig struct {
|
||||
ProductName string `json:"productName"` // 产品名
|
||||
UserSystemName string `json:"userSystemName"` // 管理员系统名称
|
||||
ShowPageFooter bool `json:"showPageFooter"` // 是否显示页脚
|
||||
PageFooterHTML string `json:"pageFooterHTML"` // 页脚HTML
|
||||
ShowVersion bool `json:"showVersion"` // 是否显示版本号
|
||||
Version string `json:"version"` // 显示的版本号
|
||||
ShowFinance bool `json:"showFinance"` // 是否显示财务相关信息
|
||||
FaviconFileId int64 `json:"faviconFileId"` // Favicon文件ID
|
||||
LogoFileId int64 `json:"logoFileId"` // 控制面板Logo文件ID
|
||||
|
||||
TimeZone string `json:"timeZone"` // 时区
|
||||
|
||||
DNSResolver struct {
|
||||
Type string `json:"type"` // 类型,参考 DNSResolverType*
|
||||
} `json:"dnsResolver"` // DNS解析设置
|
||||
|
||||
ClientIPHeaderNames string `json:"clientIPHeaderNames"` // 客户端IP获取报头名称列表
|
||||
|
||||
Server struct {
|
||||
CheckCNAME bool `json:"checkCNAME"` // 是否检查CNAME
|
||||
} `json:"server"` // 服务相关设置
|
||||
|
||||
BandwidthUnit BandwidthUnit `json:"bandwidthUnit"` // 带宽单位
|
||||
ShowTrafficCharts bool `json:"showTrafficCharts"` // 是否显示流量相关图表和数据
|
||||
ShowCacheInfoInTrafficCharts bool `json:"showCacheInfoInTrafficCharts"` // 在流量图中显示缓存相关信息
|
||||
ShowBandwidthCharts bool `json:"showBandwidthCharts"` // 是否显示带宽相关图表和数据
|
||||
|
||||
TrafficStats struct {
|
||||
BandwidthPercentile int32 `json:"bandwidthPercentile"` // 带宽百分位
|
||||
DefaultBandwidthDateRange string `json:"defaultBandwidthDateRange"` // 默认带宽周期
|
||||
BandwidthAlgo BandwidthAlgo `json:"bandwidthAlgo"` // 带宽算法
|
||||
} `json:"trafficStats"` // 流量统计相关设置
|
||||
|
||||
Portal struct {
|
||||
IsOn bool `json:"isOn"` // 是否启用
|
||||
LogoFileId int64 `json:"logoFileId"` // Logo文件ID
|
||||
} `json:"portal"` // 门户页面相关设置
|
||||
|
||||
Theme ThemeConfig `yaml:"theme" json:"theme"` // 风格模板
|
||||
}
|
||||
|
||||
func NewUserUIConfig() *UserUIConfig {
|
||||
var config = &UserUIConfig{
|
||||
ProductName: "GoEdge",
|
||||
UserSystemName: "GoEdge用户系统",
|
||||
ShowPageFooter: false,
|
||||
ShowVersion: true,
|
||||
ShowFinance: true,
|
||||
BandwidthUnit: BandwidthUnitBit,
|
||||
ShowBandwidthCharts: true,
|
||||
ShowTrafficCharts: true,
|
||||
TimeZone: "Asia/Shanghai",
|
||||
}
|
||||
|
||||
// DNS解析设置
|
||||
config.DNSResolver.Type = "default"
|
||||
|
||||
// 服务相关
|
||||
config.Server.CheckCNAME = true
|
||||
|
||||
// 流量相关
|
||||
config.TrafficStats.BandwidthPercentile = 95
|
||||
config.TrafficStats.DefaultBandwidthDateRange = "latest30days"
|
||||
return config
|
||||
}
|
||||
|
||||
type BandwidthDateRange struct {
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
DayFrom string `json:"dayFrom"`
|
||||
DayTo string `json:"dayTo"`
|
||||
}
|
||||
|
||||
const DefaultBandwidthDateRangeCode = "latest30days"
|
||||
const DefaultBandwidthPercentile int32 = 95
|
||||
|
||||
func FindAllBandwidthDateRanges() []*BandwidthDateRange {
|
||||
var dayInWeek = types.Int(timeutil.Format("w"))
|
||||
if dayInWeek == 0 {
|
||||
dayInWeek = 7
|
||||
}
|
||||
|
||||
return []*BandwidthDateRange{
|
||||
{
|
||||
Name: "今天",
|
||||
Code: "today",
|
||||
DayFrom: timeutil.Format("Y-m-d"),
|
||||
DayTo: timeutil.Format("Y-m-d"),
|
||||
},
|
||||
{
|
||||
Name: "昨天",
|
||||
Code: "yesterday",
|
||||
DayFrom: timeutil.Format("Y-m-d", time.Now().AddDate(0, 0, -1)),
|
||||
DayTo: timeutil.Format("Y-m-d", time.Now().AddDate(0, 0, -1)),
|
||||
},
|
||||
{
|
||||
Name: "近7天",
|
||||
Code: "latest7days",
|
||||
DayFrom: timeutil.Format("Y-m-d", time.Now().AddDate(0, 0, -6)),
|
||||
DayTo: timeutil.Format("Y-m-d"),
|
||||
},
|
||||
{
|
||||
Name: "上周",
|
||||
Code: "lastWeek",
|
||||
DayFrom: timeutil.Format("Y-m-d", time.Now().AddDate(0, 0, -dayInWeek-6)),
|
||||
DayTo: timeutil.Format("Y-m-d", time.Now().AddDate(0, 0, -dayInWeek)),
|
||||
},
|
||||
{
|
||||
Name: "近30天",
|
||||
Code: "latest30days",
|
||||
DayFrom: timeutil.Format("Y-m-d", time.Now().AddDate(0, 0, -29)),
|
||||
DayTo: timeutil.Format("Y-m-d"),
|
||||
},
|
||||
{
|
||||
Name: "当月",
|
||||
Code: "currentMonth",
|
||||
DayFrom: timeutil.Format("Y-m-01"),
|
||||
DayTo: timeutil.Format("Y-m-d"),
|
||||
},
|
||||
{
|
||||
Name: "上月",
|
||||
Code: "lastMonth",
|
||||
DayFrom: timeutil.Format("Y-m-01", time.Now().AddDate(0, -1, 0)),
|
||||
DayTo: timeutil.Format("Y-m-t", time.Now().AddDate(0, -1, 0)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func FindBandwidthDateRange(code string) *BandwidthDateRange {
|
||||
for _, r := range FindAllBandwidthDateRanges() {
|
||||
if r.Code == code {
|
||||
return r
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user